about summary refs log tree commit diff
path: root/third_party/emacs/exwm/exwm-xim.el
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/emacs/exwm/exwm-xim.el')
-rw-r--r--third_party/emacs/exwm/exwm-xim.el800
1 files changed, 0 insertions, 800 deletions
diff --git a/third_party/emacs/exwm/exwm-xim.el b/third_party/emacs/exwm/exwm-xim.el
deleted file mode 100644
index acf718e27f..0000000000
--- a/third_party/emacs/exwm/exwm-xim.el
+++ /dev/null
@@ -1,800 +0,0 @@
-;;; exwm-xim.el --- XIM Module for EXWM  -*- lexical-binding: t -*-
-
-;; Copyright (C) 2019-2020 Free Software Foundation, Inc.
-
-;; Author: Chris Feng <chris.w.feng@gmail.com>
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This module adds XIM support for EXWM and allows sending characters
-;; generated by any Emacs's builtin input method (info node `Input Methods')
-;; to X windows.
-
-;; This module is essentially an X input method server utilizing Emacs as
-;; its backend.  It talks with X windows through the XIM protocol.  The XIM
-;; protocol is quite flexible by itself, stating that an implementation can
-;; create network connections of various types as well as make use of an
-;; existing X connection for communication, and that an IM server may
-;; support multiple transport versions, various input styles and several
-;; event flow modals, etc.  Here we only make choices that are most popular
-;; among other IM servers and more importantly, practical for Emacs to act
-;; as an IM server:
-;;
-;; + Packets are transported on top of an X connection like most IMEs.
-;; + Only transport version 0.0 (i.e. only-CM & Property-with-CM) is
-;;   supported (same as "IM Server Developers Kit", adopted by most IMEs).
-;; + Only support static event flow, on-demand-synchronous method.
-;; + Only "root-window" input style is supported.
-
-;; To use this module, first load and enable it as follows:
-;;
-;;    (require 'exwm-xim)
-;;    (exwm-xim-enable)
-;;
-;; A keybinding for `toggle-input-method' is probably required to turn on &
-;; off an input method (default to `default-input-method').  It's bound to
-;; 'C-\' by default and can be made reachable when working with X windows:
-;;
-;;    (push ?\C-\\ exwm-input-prefix-keys)
-;;
-;; It's also required (and error-prone) to setup environment variables to
-;; make applications actually use this input method.  Typically the
-;; following lines should be inserted into '~/.xinitrc'.
-;;
-;;    export XMODIFIERS=@im=exwm-xim
-;;    export GTK_IM_MODULE=xim
-;;    export QT_IM_MODULE=xim
-;;    export CLUTTER_IM_MODULE=xim
-
-;; References:
-;; + XIM (http://www.x.org/releases/X11R7.6/doc/libX11/specs/XIM/xim.html)
-;; + IMdkit (http://xorg.freedesktop.org/archive/unsupported/lib/IMdkit/)
-;; + UIM (https://github.com/uim/uim)
-
-;;; Code:
-
-(eval-when-compile (require 'cl-lib))
-
-(require 'xcb-keysyms)
-(require 'xcb-xim)
-
-(require 'exwm-core)
-(require 'exwm-input)
-
-(defconst exwm-xim--locales
-  "@locale=\
-aa,af,ak,am,an,anp,ar,as,ast,ayc,az,be,bem,ber,bg,bhb,bho,bn,bo,br,brx,bs,byn,\
-ca,ce,cmn,crh,cs,csb,cv,cy,da,de,doi,dv,dz,el,en,es,et,eu,fa,ff,fi,fil,fo,fr,\
-fur,fy,ga,gd,gez,gl,gu,gv,ha,hak,he,hi,hne,hr,hsb,ht,hu,hy,ia,id,ig,ik,is,it,\
-iu,iw,ja,ka,kk,kl,km,kn,ko,kok,ks,ku,kw,ky,lb,lg,li,li,lij,lo,lt,lv,lzh,mag,\
-mai,mg,mhr,mi,mk,ml,mn,mni,mr,ms,mt,my,nan,nb,nds,ne,nhn,niu,nl,nn,nr,nso,oc,\
-om,or,os,pa,pa,pap,pl,ps,pt,quz,raj,ro,ru,rw,sa,sat,sc,sd,se,shs,si,sid,sk,sl,\
-so,sq,sr,ss,st,sv,sw,szl,ta,tcy,te,tg,th,the,ti,tig,tk,tl,tn,tr,ts,tt,ug,uk,\
-unm,ur,uz,ve,vi,wa,wae,wal,wo,xh,yi,yo,yue,zh,zu,\
-C,no"
-  "All supported locales (stolen from glibc).")
-
-(defconst exwm-xim--default-error
-  (make-instance 'xim:error
-                 :im-id 0
-                 :ic-id 0
-                 :flag xim:error-flag:invalid-both
-                 :error-code xim:error-code:bad-something
-                 :length 0
-                 :type 0
-                 :detail nil)
-  "Default error returned to clients.")
-
-(defconst exwm-xim--default-im-attrs
-  (list (make-instance 'xim:XIMATTR
-                       :id 0
-                       :type xim:ATTRIBUTE-VALUE-TYPE:xim-styles
-                       :length (length xlib:XNQueryInputStyle)
-                       :attribute xlib:XNQueryInputStyle))
-  "Default IM attrs returned to clients.")
-
-(defconst exwm-xim--default-ic-attrs
-  (list (make-instance 'xim:XICATTR
-                       :id 0
-                       :type xim:ATTRIBUTE-VALUE-TYPE:long-data
-                       :length (length xlib:XNInputStyle)
-                       :attribute xlib:XNInputStyle)
-        (make-instance 'xim:XICATTR
-                       :id 1
-                       :type xim:ATTRIBUTE-VALUE-TYPE:window
-                       :length (length xlib:XNClientWindow)
-                       :attribute xlib:XNClientWindow)
-        ;; Required by e.g. xterm.
-        (make-instance 'xim:XICATTR
-                       :id 2
-                       :type xim:ATTRIBUTE-VALUE-TYPE:window
-                       :length (length xlib:XNFocusWindow)
-                       :attribute xlib:XNFocusWindow))
-  "Default IC attrs returned to clients.")
-
-(defconst exwm-xim--default-styles
-  (make-instance 'xim:XIMStyles
-                 :number nil
-                 :styles (list (logior xlib:XIMPreeditNothing
-                                       xlib:XIMStatusNothing)))
-  "Default styles: root-window, i.e. no preediting or status display support.")
-
-(defconst exwm-xim--default-attributes
-  (list (make-instance 'xim:XIMATTRIBUTE
-                       :id 0
-                       :length nil
-                       :value exwm-xim--default-styles))
-  "Default IM/IC attributes returned to clients.")
-
-(defvar exwm-xim--conn nil
-  "The X connection for initiating other XIM connections.")
-(defvar exwm-xim--event-xwin nil
-  "X window for initiating new XIM connections.")
-(defvar exwm-xim--server-client-plist '(nil nil)
-  "Plist mapping server window to [X connection, client window, byte-order].")
-(defvar exwm-xim--client-server-plist '(nil nil)
-  "Plist mapping client window to server window.")
-(defvar exwm-xim--property-index 0 "For generating a unique property name.")
-(defvar exwm-xim--im-id 0 "Last IM ID.")
-(defvar exwm-xim--ic-id 0 "Last IC ID.")
-
-;; X11 atoms.
-(defvar exwm-xim--@server nil)
-(defvar exwm-xim--LOCALES nil)
-(defvar exwm-xim--TRANSPORT nil)
-(defvar exwm-xim--XIM_SERVERS nil)
-(defvar exwm-xim--_XIM_PROTOCOL nil)
-(defvar exwm-xim--_XIM_XCONNECT nil)
-
-(defun exwm-xim--on-SelectionRequest (data _synthetic)
-  "Handle SelectionRequest events on IMS window.
-
-Such events would be received when clients query for LOCALES or TRANSPORT."
-  (exwm--log)
-  (let ((evt (make-instance 'xcb:SelectionRequest))
-        value fake-event)
-    (xcb:unmarshal evt data)
-    (with-slots (time requestor selection target property) evt
-      (setq value (cond ((= target exwm-xim--LOCALES)
-                         ;; Return supported locales.
-                         exwm-xim--locales)
-                        ((= target exwm-xim--TRANSPORT)
-                         ;; Use XIM over an X connection.
-                         "@transport=X/")))
-      (when value
-        ;; Change the property.
-        (xcb:+request exwm-xim--conn
-            (make-instance 'xcb:ChangeProperty
-                           :mode xcb:PropMode:Replace
-                           :window requestor
-                           :property property
-                           :type target
-                           :format 8
-                           :data-len (length value)
-                           :data value))
-        ;; Send a SelectionNotify event.
-        (setq fake-event (make-instance 'xcb:SelectionNotify
-                                        :time time
-                                        :requestor requestor
-                                        :selection selection
-                                        :target target
-                                        :property property))
-        (xcb:+request exwm-xim--conn
-            (make-instance 'xcb:SendEvent
-                           :propagate 0
-                           :destination requestor
-                           :event-mask xcb:EventMask:NoEvent
-                           :event (xcb:marshal fake-event exwm-xim--conn)))
-        (xcb:flush exwm-xim--conn)))))
-
-(cl-defun exwm-xim--on-ClientMessage-0 (data _synthetic)
-  "Handle ClientMessage event on IMS window (new connection).
-
-Such events would be received when clients request for _XIM_XCONNECT.
-A new X connection and server window would be created to communicate with
-this client."
-  (exwm--log)
-  (let ((evt (make-instance 'xcb:ClientMessage))
-        conn client-xwin server-xwin)
-    (xcb:unmarshal evt data)
-    (with-slots (window type data) evt
-      (unless (= type exwm-xim--_XIM_XCONNECT)
-        ;; Only handle _XIM_XCONNECT.
-        (exwm--log "Ignore ClientMessage %s" type)
-        (cl-return-from exwm-xim--on-ClientMessage-0))
-      (setq client-xwin (elt (slot-value data 'data32) 0)
-            ;; Create a new X connection and a new server window.
-            conn (xcb:connect)
-            server-xwin (xcb:generate-id conn))
-      (set-process-query-on-exit-flag (slot-value conn 'process) nil)
-      ;; Store this client.
-      (plist-put exwm-xim--server-client-plist server-xwin
-                 `[,conn ,client-xwin nil])
-      (plist-put exwm-xim--client-server-plist client-xwin server-xwin)
-      ;; Select DestroyNotify events on this client window.
-      (xcb:+request exwm-xim--conn
-          (make-instance 'xcb:ChangeWindowAttributes
-                         :window client-xwin
-                         :value-mask xcb:CW:EventMask
-                         :event-mask xcb:EventMask:StructureNotify))
-      (xcb:flush exwm-xim--conn)
-      ;; Handle ClientMessage events from this new connection.
-      (xcb:+event conn 'xcb:ClientMessage #'exwm-xim--on-ClientMessage)
-      ;; Create a communication window.
-      (xcb:+request conn
-          (make-instance 'xcb:CreateWindow
-                         :depth 0
-                         :wid server-xwin
-                         :parent exwm--root
-                         :x 0
-                         :y 0
-                         :width 1
-                         :height 1
-                         :border-width 0
-                         :class xcb:WindowClass:InputOutput
-                         :visual 0
-                         :value-mask xcb:CW:OverrideRedirect
-                         :override-redirect 1))
-      (xcb:flush conn)
-      ;; Send connection establishment ClientMessage.
-      (setf window client-xwin
-            (slot-value data 'data32) `(,server-xwin 0 0 0 0))
-      (slot-makeunbound data 'data8)
-      (slot-makeunbound data 'data16)
-      (xcb:+request exwm-xim--conn
-          (make-instance 'xcb:SendEvent
-                         :propagate 0
-                         :destination client-xwin
-                         :event-mask xcb:EventMask:NoEvent
-                         :event (xcb:marshal evt exwm-xim--conn)))
-      (xcb:flush exwm-xim--conn))))
-
-(cl-defun exwm-xim--on-ClientMessage (data _synthetic)
-  "Handle ClientMessage event on IMS communication window (request).
-
-Such events would be received when clients request for _XIM_PROTOCOL.
-The actual XIM request is in client message data or a property."
-  (exwm--log)
-  (let ((evt (make-instance 'xcb:ClientMessage))
-        conn client-xwin server-xwin)
-    (xcb:unmarshal evt data)
-    (with-slots (format window type data) evt
-      (unless (= type exwm-xim--_XIM_PROTOCOL)
-        (exwm--log "Ignore ClientMessage %s" type)
-        (cl-return-from exwm-xim--on-ClientMessage))
-      (setq server-xwin window
-            conn (plist-get exwm-xim--server-client-plist server-xwin)
-            client-xwin (elt conn 1)
-            conn (elt conn 0))
-      (cond ((= format 8)
-             ;; Data.
-             (exwm-xim--on-request (vconcat (slot-value data 'data8))
-                                   conn client-xwin server-xwin))
-            ((= format 32)
-             ;; Atom.
-             (with-slots (data32) data
-               (with-slots (value)
-                   (xcb:+request-unchecked+reply conn
-                       (make-instance 'xcb:GetProperty
-                                      :delete 1
-                                      :window server-xwin
-                                      :property (elt data32 1)
-                                      :type xcb:GetPropertyType:Any
-                                      :long-offset 0
-                                      :long-length (elt data32 0)))
-                 (when (> (length value) 0)
-                   (exwm-xim--on-request value conn client-xwin
-                                         server-xwin)))))))))
-
-(defun exwm-xim--on-request (data conn client-xwin server-xwin)
-  "Handle an XIM reuqest."
-  (exwm--log)
-  (let ((opcode (elt data 0))
-        ;; Let-bind `xim:lsb' to make pack/unpack functions work correctly.
-        (xim:lsb (elt (plist-get exwm-xim--server-client-plist server-xwin) 2))
-        req replies)
-    (cond ((= opcode xim:opcode:error)
-           (exwm--log "ERROR: %s" data))
-          ((= opcode xim:opcode:connect)
-           (exwm--log "CONNECT")
-           (setq xim:lsb (= (elt data 4) xim:connect-byte-order:lsb-first))
-           ;; Store byte-order.
-           (setf (elt (plist-get exwm-xim--server-client-plist server-xwin) 2)
-                 xim:lsb)
-           (setq req (make-instance 'xim:connect))
-           (xcb:unmarshal req data)
-           (if (and (= (slot-value req 'major-version) 1)
-                    (= (slot-value req 'minor-version) 0)
-                    ;; Do not support authentication.
-                    (= (slot-value req 'number) 0))
-               ;; Accept the connection.
-               (push (make-instance 'xim:connect-reply) replies)
-             ;; Deny it.
-             (push exwm-xim--default-error replies)))
-          ((memq opcode (list xim:opcode:auth-required
-                              xim:opcode:auth-reply
-                              xim:opcode:auth-next
-                              xim:opcode:auth-ng))
-           (exwm--log "AUTH: %d" opcode)
-           ;; Deny any attempt to make authentication.
-           (push exwm-xim--default-error replies))
-          ((= opcode xim:opcode:disconnect)
-           (exwm--log "DISCONNECT")
-           ;; Gracefully disconnect from the client.
-           (exwm-xim--make-request (make-instance 'xim:disconnect-reply)
-                                   conn client-xwin)
-           ;; Destroy the communication window & connection.
-           (xcb:+request conn
-               (make-instance 'xcb:DestroyWindow
-                              :window server-xwin))
-           (xcb:disconnect conn)
-           ;; Clean up cache.
-           (cl-remf exwm-xim--server-client-plist server-xwin)
-           (cl-remf exwm-xim--client-server-plist client-xwin))
-          ((= opcode xim:opcode:open)
-           (exwm--log "OPEN")
-           ;; Note: We make no check here.
-           (setq exwm-xim--im-id (if (< exwm-xim--im-id #xffff)
-                                     (1+ exwm-xim--im-id)
-                                   1))
-           (setq replies
-                 (list
-                  (make-instance 'xim:open-reply
-                                 :im-id exwm-xim--im-id
-                                 :im-attrs-length nil
-                                 :im-attrs exwm-xim--default-im-attrs
-                                 :ic-attrs-length nil
-                                 :ic-attrs exwm-xim--default-ic-attrs)
-                  (make-instance 'xim:set-event-mask
-                                 :im-id exwm-xim--im-id
-                                 :ic-id 0
-                                 ;; Static event flow.
-                                 :forward-event-mask xcb:EventMask:KeyPress
-                                 ;; on-demand-synchronous method.
-                                 :synchronous-event-mask
-                                 xcb:EventMask:NoEvent))))
-          ((= opcode xim:opcode:close)
-           (exwm--log "CLOSE")
-           (setq req (make-instance 'xim:close))
-           (xcb:unmarshal req data)
-           (push (make-instance 'xim:close-reply
-                                :im-id (slot-value req 'im-id))
-                 replies))
-          ((= opcode xim:opcode:trigger-notify)
-           (exwm--log "TRIGGER-NOTIFY")
-           ;; Only static event flow modal is supported.
-           (push exwm-xim--default-error replies))
-          ((= opcode xim:opcode:encoding-negotiation)
-           (exwm--log "ENCODING-NEGOTIATION")
-           (setq req (make-instance 'xim:encoding-negotiation))
-           (xcb:unmarshal req data)
-           (let ((index (cl-position "COMPOUND_TEXT"
-                                     (mapcar (lambda (i) (slot-value i 'name))
-                                             (slot-value req 'names))
-                                     :test #'equal)))
-             (unless index
-               ;; Fallback to portable character encoding (a subset of ASCII).
-               (setq index -1))
-             (push (make-instance 'xim:encoding-negotiation-reply
-                                  :im-id (slot-value req 'im-id)
-                                  :category
-                                  xim:encoding-negotiation-reply-category:name
-                                  :index index)
-                   replies)))
-          ((= opcode xim:opcode:query-extension)
-           (exwm--log "QUERY-EXTENSION")
-           (setq req (make-instance 'xim:query-extension))
-           (xcb:unmarshal req data)
-           (push (make-instance 'xim:query-extension-reply
-                                :im-id (slot-value req 'im-id)
-                                ;; No extension support.
-                                :length 0
-                                :extensions nil)
-                 replies))
-          ((= opcode xim:opcode:set-im-values)
-           (exwm--log "SET-IM-VALUES")
-           ;; There's only one possible input method attribute.
-           (setq req (make-instance 'xim:set-im-values))
-           (xcb:unmarshal req data)
-           (push (make-instance 'xim:set-im-values-reply
-                                :im-id (slot-value req 'im-id))
-                 replies))
-          ((= opcode xim:opcode:get-im-values)
-           (exwm--log "GET-IM-VALUES")
-           (setq req (make-instance 'xim:get-im-values))
-           (let (im-attributes-id)
-             (xcb:unmarshal req data)
-             (setq im-attributes-id (slot-value req 'im-attributes-id))
-             (if (cl-notevery (lambda (i) (= i 0)) im-attributes-id)
-                 ;; Only support one IM attributes.
-                 (push (make-instance 'xim:error
-                                      :im-id (slot-value req 'im-id)
-                                      :ic-id 0
-                                      :flag xim:error-flag:invalid-ic-id
-                                      :error-code xim:error-code:bad-something
-                                      :length 0
-                                      :type 0
-                                      :detail nil)
-                       replies)
-               (push
-                (make-instance 'xim:get-im-values-reply
-                               :im-id (slot-value req 'im-id)
-                               :length nil
-                               :im-attributes exwm-xim--default-attributes)
-                replies))))
-          ((= opcode xim:opcode:create-ic)
-           (exwm--log "CREATE-IC")
-           (setq req (make-instance 'xim:create-ic))
-           (xcb:unmarshal req data)
-           ;; Note: The ic-attributes slot is ignored.
-           (setq exwm-xim--ic-id (if (< exwm-xim--ic-id #xffff)
-                                     (1+ exwm-xim--ic-id)
-                                   1))
-           (push (make-instance 'xim:create-ic-reply
-                                :im-id (slot-value req 'im-id)
-                                :ic-id exwm-xim--ic-id)
-                 replies))
-          ((= opcode xim:opcode:destroy-ic)
-           (exwm--log "DESTROY-IC")
-           (setq req (make-instance 'xim:destroy-ic))
-           (xcb:unmarshal req data)
-           (push (make-instance 'xim:destroy-ic-reply
-                                :im-id (slot-value req 'im-id)
-                                :ic-id (slot-value req 'ic-id))
-                 replies))
-          ((= opcode xim:opcode:set-ic-values)
-           (exwm--log "SET-IC-VALUES")
-           (setq req (make-instance 'xim:set-ic-values))
-           (xcb:unmarshal req data)
-           ;; We don't distinguish between input contexts.
-           (push (make-instance 'xim:set-ic-values-reply
-                                :im-id (slot-value req 'im-id)
-                                :ic-id (slot-value req 'ic-id))
-                 replies))
-          ((= opcode xim:opcode:get-ic-values)
-           (exwm--log "GET-IC-VALUES")
-           (setq req (make-instance 'xim:get-ic-values))
-           (xcb:unmarshal req data)
-           (push (make-instance 'xim:get-ic-values-reply
-                                :im-id (slot-value req 'im-id)
-                                :ic-id (slot-value req 'ic-id)
-                                :length nil
-                                :ic-attributes exwm-xim--default-attributes)
-                 replies))
-          ((= opcode xim:opcode:set-ic-focus)
-           (exwm--log "SET-IC-FOCUS")
-           ;; All input contexts are the same.
-           )
-          ((= opcode xim:opcode:unset-ic-focus)
-           (exwm--log "UNSET-IC-FOCUS")
-           ;; All input contexts are the same.
-           )
-          ((= opcode xim:opcode:forward-event)
-           (exwm--log "FORWARD-EVENT")
-           (setq req (make-instance 'xim:forward-event))
-           (xcb:unmarshal req data)
-           (exwm-xim--handle-forward-event-request req xim:lsb conn
-                                                   client-xwin))
-          ((= opcode xim:opcode:sync)
-           (exwm--log "SYNC")
-           (setq req (make-instance 'xim:sync))
-           (xcb:unmarshal req data)
-           (push (make-instance 'xim:sync-reply
-                                :im-id (slot-value req 'im-id)
-                                :ic-id (slot-value req 'ic-id))
-                 replies))
-          ((= opcode xim:opcode:sync-reply)
-           (exwm--log "SYNC-REPLY"))
-          ((= opcode xim:opcode:reset-ic)
-           (exwm--log "RESET-IC")
-           ;; No context-specific data saved.
-           (setq req (make-instance 'xim:reset-ic))
-           (xcb:unmarshal req data)
-           (push (make-instance 'xim:reset-ic-reply
-                                :im-id (slot-value req 'im-id)
-                                :ic-id (slot-value req 'ic-id)
-                                :length 0
-                                :string "")
-                 replies))
-          ((memq opcode (list xim:opcode:str-conversion-reply
-                              xim:opcode:preedit-start-reply
-                              xim:opcode:preedit-caret-reply))
-           (exwm--log "PREEDIT: %d" opcode)
-           ;; No preedit support.
-           (push exwm-xim--default-error replies))
-          (t
-           (exwm--log "Bad protocol")
-           (push exwm-xim--default-error replies)))
-    ;; Actually send the replies.
-    (when replies
-      (mapc (lambda (reply)
-              (exwm-xim--make-request reply conn client-xwin))
-            replies)
-      (xcb:flush conn))))
-
-(defun exwm-xim--handle-forward-event-request (req lsb conn client-xwin)
-  (let ((im-func (with-current-buffer (window-buffer)
-                   input-method-function))
-        key-event keysym keysyms event result)
-    ;; Note: The flag slot is ignored.
-    ;; Do conversion in client's byte-order.
-    (let ((xcb:lsb lsb))
-      (setq key-event (make-instance 'xcb:KeyPress))
-      (xcb:unmarshal key-event (slot-value req 'event)))
-    (with-slots (detail state) key-event
-      (setq keysym (xcb:keysyms:keycode->keysym exwm-xim--conn detail
-                                                state))
-      (when (/= (car keysym) 0)
-        (setq event (xcb:keysyms:keysym->event
-                     exwm-xim--conn
-                     (car keysym)
-                     (logand state (lognot (cdr keysym)))))))
-    (while (or (slot-value req 'event) unread-command-events)
-      (unless (slot-value req 'event)
-        (setq event (pop unread-command-events))
-        ;; Handle events in (t . EVENT) format.
-        (when (and (consp event)
-                   (eq (car event) t))
-          (setq event (cdr event))))
-      (if (or (not im-func)
-              ;; `list' is the default method.
-              (eq im-func #'list)
-              (not event)
-              ;; Select only printable keys.
-              (not (integerp event)) (> #x20 event) (< #x7e event))
-          ;; Either there is no active input method, or invalid key
-          ;; is detected.
-          (with-slots ((raw-event event)
-                       im-id ic-id serial-number)
-              req
-            (if raw-event
-                (setq event raw-event)
-              (setq keysyms (xcb:keysyms:event->keysyms exwm-xim--conn event))
-              (with-slots (detail state) key-event
-                (setf detail (xcb:keysyms:keysym->keycode exwm-xim--conn
-                                                          (caar keysyms))
-                      state (cdar keysyms)))
-              (setq event (let ((xcb:lsb lsb))
-                            (xcb:marshal key-event conn))))
-            (when event
-              (exwm-xim--make-request
-               (make-instance 'xim:forward-event
-                              :im-id im-id
-                              :ic-id ic-id
-                              :flag xim:commit-flag:synchronous
-                              :serial-number serial-number
-                              :event event)
-               conn client-xwin)))
-        (when (eq exwm--selected-input-mode 'char-mode)
-          ;; Grab keyboard temporarily for char-mode.
-          (exwm-input--grab-keyboard))
-        (unwind-protect
-            (with-temp-buffer
-              ;; Always show key strokes.
-              (let ((input-method-use-echo-area t)
-                    (exwm-input-line-mode-passthrough t))
-                (setq result (funcall im-func event))
-                ;; Clear echo area for the input method.
-                (message nil)
-                ;; This also works for portable character encoding.
-                (setq result
-                      (encode-coding-string (concat result)
-                                            'compound-text-with-extensions))
-                (exwm-xim--make-request
-                 (make-instance 'xim:commit-x-lookup-chars
-                                :im-id (slot-value req 'im-id)
-                                :ic-id (slot-value req 'ic-id)
-                                :flag (logior xim:commit-flag:synchronous
-                                              xim:commit-flag:x-lookup-chars)
-                                :length (length result)
-                                :string result)
-                 conn client-xwin)))
-          (when (eq exwm--selected-input-mode 'char-mode)
-            (exwm-input--release-keyboard))))
-      (xcb:flush conn)
-      (setf event nil
-            (slot-value req 'event) nil))))
-
-(defun exwm-xim--make-request (req conn client-xwin)
-  "Make an XIM request REQ via connection CONN.
-
-CLIENT-XWIN would receive a ClientMessage event either telling the client
-the request data or where to fetch the data."
-  (exwm--log)
-  (let ((data (xcb:marshal req))
-        property format client-message-data client-message)
-    (if (<= (length data) 20)
-        ;; Send short requests directly with client messages.
-        (setq format 8
-              ;; Pad to 20 bytes.
-              data (append data (make-list (- 20 (length data)) 0))
-              client-message-data (make-instance 'xcb:ClientMessageData
-                                                 :data8 data))
-      ;; Send long requests with properties.
-      (setq property (exwm--intern-atom (format "_EXWM_XIM_%x"
-                                                exwm-xim--property-index)))
-      (cl-incf exwm-xim--property-index)
-      (xcb:+request conn
-          (make-instance 'xcb:ChangeProperty
-                         :mode xcb:PropMode:Append
-                         :window client-xwin
-                         :property property
-                         :type xcb:Atom:STRING
-                         :format 8
-                         :data-len (length data)
-                         :data data))
-      ;; Also send a client message to notify the client about this property.
-      (setq format 32
-            client-message-data (make-instance 'xcb:ClientMessageData
-                                               :data32 `(,(length data)
-                                                         ,property
-                                                         ;; Pad to 20 bytes.
-                                                         0 0 0))))
-    ;; Send the client message.
-    (setq client-message (make-instance 'xcb:ClientMessage
-                                        :format format
-                                        :window client-xwin
-                                        :type exwm-xim--_XIM_PROTOCOL
-                                        :data client-message-data))
-    (xcb:+request conn
-        (make-instance 'xcb:SendEvent
-                       :propagate 0
-                       :destination client-xwin
-                       :event-mask xcb:EventMask:NoEvent
-                       :event (xcb:marshal client-message conn)))))
-
-(defun exwm-xim--on-DestroyNotify (data synthetic)
-  "Do cleanups on receiving DestroyNotify event.
-
-Such event would be received when the client window is destroyed."
-  (exwm--log)
-  (unless synthetic
-    (let ((evt (make-instance 'xcb:DestroyNotify))
-          conn client-xwin server-xwin)
-      (xcb:unmarshal evt data)
-      (setq client-xwin (slot-value evt 'window)
-            server-xwin (plist-get exwm-xim--client-server-plist client-xwin))
-      (when server-xwin
-        (setq conn (aref (plist-get exwm-xim--server-client-plist server-xwin)
-                         0))
-        (cl-remf exwm-xim--server-client-plist server-xwin)
-        (cl-remf exwm-xim--client-server-plist client-xwin)
-        ;; Destroy the communication window & connection.
-        (xcb:+request conn
-            (make-instance 'xcb:DestroyWindow
-                           :window server-xwin))
-        (xcb:disconnect conn)))))
-
-(cl-defun exwm-xim--init ()
-  "Initialize the XIM module."
-  (exwm--log)
-  (when exwm-xim--conn
-    (cl-return-from exwm-xim--init))
-  ;; Initialize atoms.
-  (setq exwm-xim--@server (exwm--intern-atom "@server=exwm-xim")
-        exwm-xim--LOCALES (exwm--intern-atom "LOCALES")
-        exwm-xim--TRANSPORT (exwm--intern-atom "TRANSPORT")
-        exwm-xim--XIM_SERVERS (exwm--intern-atom "XIM_SERVERS")
-        exwm-xim--_XIM_PROTOCOL (exwm--intern-atom "_XIM_PROTOCOL")
-        exwm-xim--_XIM_XCONNECT (exwm--intern-atom "_XIM_XCONNECT"))
-  ;; Create a new connection and event window.
-  (setq exwm-xim--conn (xcb:connect)
-        exwm-xim--event-xwin (xcb:generate-id exwm-xim--conn))
-  (set-process-query-on-exit-flag (slot-value exwm-xim--conn 'process) nil)
-  ;; Initialize xcb:keysyms module.
-  (xcb:keysyms:init exwm-xim--conn)
-  ;; Listen to SelectionRequest event for connection establishment.
-  (xcb:+event exwm-xim--conn 'xcb:SelectionRequest
-              #'exwm-xim--on-SelectionRequest)
-  ;; Listen to ClientMessage event on IMS window for new XIM connection.
-  (xcb:+event exwm-xim--conn 'xcb:ClientMessage #'exwm-xim--on-ClientMessage-0)
-  ;; Listen to DestroyNotify event to do cleanups.
-  (xcb:+event exwm-xim--conn 'xcb:DestroyNotify #'exwm-xim--on-DestroyNotify)
-  ;; Create the event window.
-  (xcb:+request exwm-xim--conn
-      (make-instance 'xcb:CreateWindow
-                     :depth 0
-                     :wid exwm-xim--event-xwin
-                     :parent exwm--root
-                     :x 0
-                     :y 0
-                     :width 1
-                     :height 1
-                     :border-width 0
-                     :class xcb:WindowClass:InputOutput
-                     :visual 0
-                     :value-mask xcb:CW:OverrideRedirect
-                     :override-redirect 1))
-  ;; Set the selection owner.
-  (xcb:+request exwm-xim--conn
-      (make-instance 'xcb:SetSelectionOwner
-                     :owner exwm-xim--event-xwin
-                     :selection exwm-xim--@server
-                     :time xcb:Time:CurrentTime))
-  ;; Set XIM_SERVERS property on the root window.
-  (xcb:+request exwm-xim--conn
-      (make-instance 'xcb:ChangeProperty
-                     :mode xcb:PropMode:Prepend
-                     :window exwm--root
-                     :property exwm-xim--XIM_SERVERS
-                     :type xcb:Atom:ATOM
-                     :format 32
-                     :data-len 1
-                     :data (funcall (if xcb:lsb
-                                        #'xcb:-pack-u4-lsb
-                                      #'xcb:-pack-u4)
-                                    exwm-xim--@server)))
-  (xcb:flush exwm-xim--conn))
-
-(cl-defun exwm-xim--exit ()
-  "Exit the XIM module."
-  (exwm--log)
-  ;; Close IMS communication connections.
-  (mapc (lambda (i)
-          (when (vectorp i)
-            (xcb:disconnect (elt i 0))))
-        exwm-xim--server-client-plist)
-  ;; Close the IMS connection.
-  (unless exwm-xim--conn
-    (cl-return-from exwm-xim--exit))
-  ;; Remove exwm-xim from XIM_SERVERS.
-  (let ((reply (xcb:+request-unchecked+reply exwm-xim--conn
-                   (make-instance 'xcb:GetProperty
-                                  :delete 1
-                                  :window exwm--root
-                                  :property exwm-xim--XIM_SERVERS
-                                  :type xcb:Atom:ATOM
-                                  :long-offset 0
-                                  :long-length 1000)))
-        unpacked-reply pack unpack)
-    (unless reply
-      (cl-return-from exwm-xim--exit))
-    (setq reply (slot-value reply 'value))
-    (unless (> (length reply) 4)
-      (cl-return-from exwm-xim--exit))
-    (setq reply (vconcat reply)
-          pack (if xcb:lsb #'xcb:-pack-u4-lsb #'xcb:-pack-u4)
-          unpack (if xcb:lsb #'xcb:-unpack-u4-lsb #'xcb:-unpack-u4))
-    (dotimes (i (/ (length reply) 4))
-      (push (funcall unpack reply (* i 4)) unpacked-reply))
-    (setq unpacked-reply (delq exwm-xim--@server unpacked-reply)
-          reply (mapcar pack unpacked-reply))
-    (xcb:+request exwm-xim--conn
-        (make-instance 'xcb:ChangeProperty
-                       :mode xcb:PropMode:Replace
-                       :window exwm--root
-                       :property exwm-xim--XIM_SERVERS
-                       :type xcb:Atom:ATOM
-                       :format 32
-                       :data-len (length reply)
-                       :data reply))
-    (xcb:flush exwm-xim--conn))
-  (xcb:disconnect exwm-xim--conn)
-  (setq exwm-xim--conn nil))
-
-(defun exwm-xim-enable ()
-  "Enable XIM support for EXWM."
-  (exwm--log)
-  (add-hook 'exwm-init-hook #'exwm-xim--init)
-  (add-hook 'exwm-exit-hook #'exwm-xim--exit))
-
-
-
-(provide 'exwm-xim)
-
-;;; exwm-xim.el ends here