about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChris Feng <chris.w.feng@gmail.com>2018-02-21T16·26+0800
committerChris Feng <chris.w.feng@gmail.com>2018-02-21T16·26+0800
commit6200417697544317ee91badd702654def9a1d645 (patch)
tree603bea3cd7dd655d55dba53aec8864b92c4f7162
parent86f2215be3db25a6b6aacd6f8b0cb132b049e034 (diff)
Grab global keys on top-level X windows
* exwm-input.el (exwm-input--on-CreateNotify): New function for
grabbing global keys on newly created X windows.
(exwm-input--update-global-prefix-keys): Grab global keys on top-level
X windows instead of the root window.
(exwm-input--grab-global-prefix-keys): New function for grabbing
global keys on X windows.
(exwm-input--release-keyboard): Grab global keys in char-mode.
(exwm-input--init): Select CreateNotify events.

* exwm-core.el (exwm--unlock):
* exwm-input.el (exwm-input--on-FocusIn, exwm-input--init): Do not
handle FocusIn events on the root window.
-rw-r--r--exwm-core.el3
-rw-r--r--exwm-input.el80
2 files changed, 41 insertions, 42 deletions
diff --git a/exwm-core.el b/exwm-core.el
index f64a7f25fa31..41c3b5772495 100644
--- a/exwm-core.el
+++ b/exwm-core.el
@@ -93,8 +93,7 @@
                      :window exwm--root
                      :value-mask xcb:CW:EventMask
                      :event-mask (eval-when-compile
-                                   (logior xcb:EventMask:FocusChange
-                                           xcb:EventMask:SubstructureRedirect
+                                   (logior xcb:EventMask:SubstructureRedirect
                                            xcb:EventMask:StructureNotify))))
   (xcb:flush exwm--connection))
 
diff --git a/exwm-input.el b/exwm-input.el
index 8102eb2ca79f..ea3d65934026 100644
--- a/exwm-input.el
+++ b/exwm-input.el
@@ -212,16 +212,6 @@ ARGS are additional arguments to CALLBACK."
                (cdr exwm-input--timestamp-callback))
         (setq exwm-input--timestamp-callback nil)))))
 
-(defun exwm-input--on-FocusIn (data _synthetic)
-  "Handle FocusIn events."
-  (let ((obj (make-instance 'xcb:FocusIn)))
-    (xcb:unmarshal obj data)
-    (with-slots (mode) obj
-      ;; Revert input focus back to Emacs frame / X window when it's set on
-      ;; the root window.
-      (x-focus-frame exwm-workspace--current)
-      (select-window (frame-selected-window exwm-workspace--current)))))
-
 (defun exwm-input--on-EnterNotify (data _synthetic)
   "Handle EnterNotify events."
   (let ((evt (make-instance 'xcb:EnterNotify))
@@ -428,42 +418,51 @@ ARGS are additional arguments to CALLBACK."
         (funcall exwm--on-KeyPress obj data)
       (exwm-input--on-KeyPress-char-mode obj))))
 
+(defun exwm-input--on-CreateNotify (data _synthetic)
+  "Handle CreateNotify events."
+  (let ((evt (make-instance 'xcb:CreateNotify)))
+    (xcb:unmarshal evt data)
+    (with-slots (window) evt
+      (exwm-input--grab-global-prefix-keys window))))
+
 (defun exwm-input--update-global-prefix-keys ()
   "Update `exwm-input--global-prefix-keys'."
   (when exwm--connection
-    (let ((original exwm-input--global-prefix-keys)
-          keysym keycode grab-key)
+    (let ((original exwm-input--global-prefix-keys))
       (setq exwm-input--global-prefix-keys nil)
       (dolist (i exwm-input--global-keys)
         (cl-pushnew (elt i 0) exwm-input--global-prefix-keys))
-      ;; Stop here if the global prefix keys are update-to-date and
-      ;; there's no new workspace.
       (unless (equal original exwm-input--global-prefix-keys)
-        (setq grab-key (make-instance 'xcb:GrabKey
-                                      :owner-events 0
-                                      :grab-window exwm--root
-                                      :modifiers nil
-                                      :key nil
-                                      :pointer-mode xcb:GrabMode:Async
-                                      :keyboard-mode xcb:GrabMode:Async))
-        (dolist (k exwm-input--global-prefix-keys)
-          (setq keysym (xcb:keysyms:event->keysym exwm--connection k)
-                keycode (xcb:keysyms:keysym->keycode exwm--connection
-                                                     (car keysym)))
-          (setf (slot-value grab-key 'modifiers) (cdr keysym)
-                (slot-value grab-key 'key) keycode)
-          (when (or (= 0 keycode)
-                    (xcb:+request-checked+request-check exwm--connection
-                        grab-key)
-                    ;; Also grab this key with num-lock mask set.
-                    (when (/= 0 xcb:keysyms:num-lock-mask)
-                      (setf (slot-value grab-key 'modifiers)
-                            (logior (cdr keysym)
-                                    xcb:keysyms:num-lock-mask))
-                      (xcb:+request-checked+request-check exwm--connection
-                          grab-key)))
-            (user-error "[EXWM] Failed to grab key: %s"
-                        (single-key-description k))))))))
+        (apply #'exwm-input--grab-global-prefix-keys
+               (slot-value (xcb:+request-unchecked+reply exwm--connection
+                               (make-instance 'xcb:QueryTree
+                                              :window exwm--root))
+                           'children))))))
+
+(defun exwm-input--grab-global-prefix-keys (&rest xwins)
+  (let ((req (make-instance 'xcb:GrabKey
+                            :owner-events 0
+                            :grab-window nil
+                            :modifiers nil
+                            :key nil
+                            :pointer-mode xcb:GrabMode:Async
+                            :keyboard-mode xcb:GrabMode:Async))
+        keysym keycode)
+    (dolist (k exwm-input--global-prefix-keys)
+      (setq keysym (xcb:keysyms:event->keysym exwm--connection k)
+            keycode (xcb:keysyms:keysym->keycode exwm--connection
+                                                 (car keysym)))
+      (setf (slot-value req 'modifiers) (cdr keysym)
+            (slot-value req 'key) keycode)
+      (dolist (xwin xwins)
+        (setf (slot-value req 'grab-window) xwin)
+        (xcb:+request exwm--connection req)
+        ;; Also grab this key with num-lock mask set.
+        (when (/= 0 xcb:keysyms:num-lock-mask)
+          (setf (slot-value req 'modifiers)
+                (logior (cdr keysym) xcb:keysyms:num-lock-mask))
+          (xcb:+request exwm--connection req))))
+    (xcb:flush exwm--connection)))
 
 ;;;###autoload
 (defun exwm-input-set-key (key command)
@@ -635,6 +634,7 @@ called interactively.  Only invoke it non-interactively in configuration."
                              :grab-window id
                              :modifiers xcb:ModMask:Any))
       (exwm--log "Failed to release keyboard for #x%x" id))
+    (exwm-input--grab-global-prefix-keys id)
     (with-current-buffer (exwm--id->buffer id)
       (setq exwm--on-KeyPress #'exwm-input--on-KeyPress-char-mode))))
 
@@ -877,13 +877,13 @@ Its usage is the same with `exwm-input-set-simulation-keys'."
   ;; Attach event listeners
   (xcb:+event exwm--connection 'xcb:PropertyNotify
               #'exwm-input--on-PropertyNotify)
+  (xcb:+event exwm--connection 'xcb:CreateNotify #'exwm-input--on-CreateNotify)
   (xcb:+event exwm--connection 'xcb:KeyPress #'exwm-input--on-KeyPress)
   (xcb:+event exwm--connection 'xcb:ButtonPress #'exwm-input--on-ButtonPress)
   (xcb:+event exwm--connection 'xcb:ButtonRelease
               #'exwm-floating--stop-moveresize)
   (xcb:+event exwm--connection 'xcb:MotionNotify
               #'exwm-floating--do-moveresize)
-  (xcb:+event exwm--connection 'xcb:FocusIn #'exwm-input--on-FocusIn)
   (when mouse-autoselect-window
     (xcb:+event exwm--connection 'xcb:EnterNotify
                 #'exwm-input--on-EnterNotify))