about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChris Feng <chris.w.feng@gmail.com>2015-09-27T11·31+0800
committerChris Feng <chris.w.feng@gmail.com>2015-09-27T11·43+0800
commit5184f0d7c1b540a6241904528d068dce288a911e (patch)
tree1f7cecd5399eb739293104f8e5dc9c6cab50b5d6
parentf685de12d464b334ba7efdfe67e989dd63a96fa0 (diff)
Work around subrs that block EXWM; other minor fixes
Some subrs (e.g. x-file-dialog) create X windows and block the execution of
EXWM, so they won't work normally.  This commit partly fixes this issue by
invoking them in a subordinate Emacs instance and trying to fetch the
result back.

* exwm.el (exwm-blocking-subrs): New variable for specify such subrs.
* exwm.el (exwm-enable, exwm--server-name, exwm--server-stop)
  (exwm--server-eval-at): The implementation.

* exwm-core.el:
* exwm-floating.el:
* exwm-layout.el:
* exwm-manage.el:
* exwm-randr.el:
  Evaluate constants at compile-time.

* README.md: Renamed from README.org to make the 'Commentary:' section
  used by GNU ELPA instead.

* exwm.el: Depends on XELB version 0.3.
-rw-r--r--README.md (renamed from README.org)9
-rw-r--r--exwm-core.el8
-rw-r--r--exwm-floating.el62
-rw-r--r--exwm-layout.el47
-rw-r--r--exwm-manage.el5
-rw-r--r--exwm-randr.el20
-rw-r--r--exwm.el79
7 files changed, 158 insertions, 72 deletions
diff --git a/README.org b/README.md
index 49ba04b33a7b..09fe470d392c 100644
--- a/README.org
+++ b/README.md
@@ -1,7 +1,7 @@
-#+TITLE: Emacs X Window Manager
+# Emacs X Window Manager
 
 EXWM (Emacs X Window Manager) is a full-featured tiling X window manager for
-Emacs built on top of [[https://github.com/ch11ng/xelb][XELB]].
+Emacs built on top of [XELB](https://github.com/ch11ng/xelb).
 It features:
 + Fully keyboard-driven operation
 + Hybrid layout modes (tiling & stacking)
@@ -9,7 +9,8 @@ It features:
 + ICCCM/EWMH compliance
 + Basic RandR support (optional)
 
-Please check the [[https://github.com/ch11ng/exwm/wiki][User Guide]] for more details.
+Please check the [User Guide](https://github.com/ch11ng/exwm/wiki)
+for more details.
 
-*Note*: If you install EXWM from source, you need to manually install XELB
+**Note**: If you install EXWM from source, you need to manually install XELB
 (either from source or GNU ELPA).
diff --git a/exwm-core.el b/exwm-core.el
index 0f39c2d344e8..1ac867865988 100644
--- a/exwm-core.el
+++ b/exwm-core.el
@@ -69,12 +69,14 @@
       (make-instance 'xcb:ChangeWindowAttributes
                      :window exwm--root
                      :value-mask xcb:CW:EventMask
-                     :event-mask (logior xcb:EventMask:StructureNotify
-                                         xcb:EventMask:SubstructureRedirect)))
+                     :event-mask (eval-when-compile
+                                   (logior xcb:EventMask:SubstructureRedirect
+                                           xcb:EventMask:StructureNotify))))
   (xcb:flush exwm--connection))
 
 (defconst exwm--client-event-mask
-  (logior xcb:EventMask:StructureNotify xcb:EventMask:PropertyChange)
+  (eval-when-compile
+    (logior xcb:EventMask:StructureNotify xcb:EventMask:PropertyChange))
   "Event mask set on all managed windows.")
 
 ;; Internal variables
diff --git a/exwm-floating.el b/exwm-floating.el
index 0994cb9914cc..59b4e4432d0f 100644
--- a/exwm-floating.el
+++ b/exwm-floating.el
@@ -247,9 +247,10 @@ are provided. You should call `xcb:flush' and restore the value of
                      :window (or frame-outer-id
                                  (frame-parameter exwm--floating-frame
                                                   'exwm-outer-id))
-                     :value-mask (logior xcb:ConfigWindow:Width
-                                         xcb:ConfigWindow:Height
-                                         xcb:ConfigWindow:StackMode)
+                     :value-mask (eval-when-compile
+                                   (logior xcb:ConfigWindow:Width
+                                           xcb:ConfigWindow:Height
+                                           xcb:ConfigWindow:StackMode))
                      :width (+ width (* 2 exwm-floating-border-width))
                      :height (+ height (* 2 exwm-floating-border-width)
                                 (window-mode-line-height)
@@ -336,18 +337,20 @@ are provided. You should call `xcb:flush' and restore the value of
                        exwm-floating--moveresize-calculate
                        `(lambda (x y)
                           (vector ,frame-id
-                                  ,(logior xcb:ConfigWindow:X
-                                           xcb:ConfigWindow:Y)
+                                  ,(eval-when-compile
+                                     (logior xcb:ConfigWindow:X
+                                             xcb:ConfigWindow:Y))
                                   (- x ,win-x) (- y ,win-y) 0 0))))
                 ((= type xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_TOPLEFT)
                  (setq cursor exwm-floating--cursor-top-left
                        exwm-floating--moveresize-calculate
                        `(lambda (x y)
                           (vector ,frame-id
-                                  ,(logior xcb:ConfigWindow:X
-                                           xcb:ConfigWindow:Y
-                                           xcb:ConfigWindow:Width
-                                           xcb:ConfigWindow:Height)
+                                  ,(eval-when-compile
+                                     (logior xcb:ConfigWindow:X
+                                             xcb:ConfigWindow:Y
+                                             xcb:ConfigWindow:Width
+                                             xcb:ConfigWindow:Height))
                                   (- x ,win-x) (- y ,win-y)
                                   (- ,(+ root-x width) x)
                                   (- ,(+ root-y height) y)))))
@@ -356,17 +359,19 @@ are provided. You should call `xcb:flush' and restore the value of
                        exwm-floating--moveresize-calculate
                        `(lambda (x y)
                           (vector ,frame-id
-                                  ,(logior xcb:ConfigWindow:Y
-                                           xcb:ConfigWindow:Height)
+                                  ,(eval-when-compile
+                                     (logior xcb:ConfigWindow:Y
+                                             xcb:ConfigWindow:Height))
                                   0 (- y ,win-y) 0 (- ,(+ root-y height) y)))))
                 ((= type xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_TOPRIGHT)
                  (setq cursor exwm-floating--cursor-top-right
                        exwm-floating--moveresize-calculate
                        `(lambda (x y)
                           (vector ,frame-id
-                                  ,(logior xcb:ConfigWindow:Y
-                                           xcb:ConfigWindow:Width
-                                           xcb:ConfigWindow:Height)
+                                  ,(eval-when-compile
+                                     (logior xcb:ConfigWindow:Y
+                                             xcb:ConfigWindow:Width
+                                             xcb:ConfigWindow:Height))
                                   0 (- y ,win-y) (- x ,(- root-x width))
                                   (- ,(+ root-y height) y)))))
                 ((= type xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_RIGHT)
@@ -380,8 +385,9 @@ are provided. You should call `xcb:flush' and restore the value of
                        exwm-floating--moveresize-calculate
                        `(lambda (x y)
                           (vector ,frame-id
-                                  ,(logior xcb:ConfigWindow:Width
-                                           xcb:ConfigWindow:Height)
+                                  ,(eval-when-compile
+                                     (logior xcb:ConfigWindow:Width
+                                             xcb:ConfigWindow:Height))
                                   0 0 (- x ,(- root-x width))
                                   (- y ,(- root-y height))))))
                 ((= type xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_BOTTOM)
@@ -396,9 +402,10 @@ are provided. You should call `xcb:flush' and restore the value of
                        exwm-floating--moveresize-calculate
                        `(lambda (x y)
                           (vector ,frame-id
-                                  ,(logior xcb:ConfigWindow:X
-                                           xcb:ConfigWindow:Width
-                                           xcb:ConfigWindow:Height)
+                                  ,(eval-when-compile
+                                     (logior xcb:ConfigWindow:X
+                                             xcb:ConfigWindow:Width
+                                             xcb:ConfigWindow:Height))
                                   (- x ,win-x)
                                   0
                                   (- ,(+ root-x width) x)
@@ -408,15 +415,17 @@ are provided. You should call `xcb:flush' and restore the value of
                        exwm-floating--moveresize-calculate
                        `(lambda (x y)
                           (vector ,frame-id
-                                  ,(logior xcb:ConfigWindow:X
-                                           xcb:ConfigWindow:Width)
+                                  ,(eval-when-compile
+                                     (logior xcb:ConfigWindow:X
+                                             xcb:ConfigWindow:Width))
                                   (- x ,win-x) 0 (- ,(+ root-x width) x) 0)))))
           ;; Select events and change cursor (should always succeed)
           (xcb:+request-unchecked+reply exwm--connection
               (make-instance 'xcb:GrabPointer
                              :owner-events 0 :grab-window frame-id
-                             :event-mask (logior xcb:EventMask:ButtonRelease
-                                                 xcb:EventMask:ButtonMotion)
+                             :event-mask (eval-when-compile
+                                           (logior xcb:EventMask:ButtonRelease
+                                                   xcb:EventMask:ButtonMotion))
                              :pointer-mode xcb:GrabMode:Async
                              :keyboard-mode xcb:GrabMode:Async
                              :confine-to xcb:Window:None
@@ -472,7 +481,7 @@ are provided. You should call `xcb:flush' and restore the value of
           (make-instance 'xcb:ConfigureWindow
                          :window (elt result 0) :value-mask (elt result 1)
                          :x (- (elt result 2) frame-x)
-                         :y (-  (elt result 3) frame-y)
+                         :y (- (elt result 3) frame-y)
                          :width (elt result 4) :height (elt result 5)))
       (xcb:flush exwm--connection))))
 
@@ -492,8 +501,9 @@ Both DELTA-X and DELTA-Y default to 1.  This command should be bound locally."
       (xcb:+request exwm--connection
           (make-instance 'xcb:ConfigureWindow
                          :window id
-                         :value-mask (logior xcb:ConfigWindow:X
-                                             xcb:ConfigWindow:Y)
+                         :value-mask (eval-when-compile
+                                       (logior xcb:ConfigWindow:X
+                                               xcb:ConfigWindow:Y))
                          :x (+ (slot-value geometry 'x) delta-x)
                          :y (+ (slot-value geometry 'y) delta-y)))
       ;; Inform the X window that its absolute position is changed
diff --git a/exwm-layout.el b/exwm-layout.el
index 4ccaef74500e..1d11dbcdca07 100644
--- a/exwm-layout.el
+++ b/exwm-layout.el
@@ -56,11 +56,12 @@
     (xcb:+request exwm--connection
         (make-instance 'xcb:ConfigureWindow
                        :window id
-                       :value-mask (logior xcb:ConfigWindow:X
-                                           xcb:ConfigWindow:Y
-                                           xcb:ConfigWindow:Width
-                                           xcb:ConfigWindow:Height
-                                           xcb:ConfigWindow:StackMode)
+                       :value-mask (eval-when-compile
+                                     (logior xcb:ConfigWindow:X
+                                             xcb:ConfigWindow:Y
+                                             xcb:ConfigWindow:Width
+                                             xcb:ConfigWindow:Height
+                                             xcb:ConfigWindow:StackMode))
                        :x x :y y :width width :height height
                        ;; In order to put non-floating window at bottom
                        :stack-mode xcb:StackMode:Below))
@@ -122,10 +123,11 @@
         (xcb:+request exwm--connection
             (make-instance 'xcb:ConfigureWindow
                            :window outer-id
-                           :value-mask (logior xcb:ConfigWindow:X
-                                               xcb:ConfigWindow:Y
-                                               xcb:ConfigWindow:Width
-                                               xcb:ConfigWindow:Height)
+                           :value-mask (eval-when-compile
+                                         (logior xcb:ConfigWindow:X
+                                                 xcb:ConfigWindow:Y
+                                                 xcb:ConfigWindow:Width
+                                                 xcb:ConfigWindow:Height))
                            :x 0 :y 0
                            :width (frame-pixel-width exwm-workspace--current)
                            :height (frame-pixel-height
@@ -134,10 +136,11 @@
     (xcb:+request exwm--connection
         (make-instance 'xcb:ConfigureWindow
                        :window exwm--id
-                       :value-mask (logior xcb:ConfigWindow:X
-                                           xcb:ConfigWindow:Y
-                                           xcb:ConfigWindow:Width
-                                           xcb:ConfigWindow:Height)
+                       :value-mask (eval-when-compile
+                                     (logior xcb:ConfigWindow:X
+                                             xcb:ConfigWindow:Y
+                                             xcb:ConfigWindow:Width
+                                             xcb:ConfigWindow:Height))
                        :x 0 :y 0
                        :width (frame-pixel-width exwm-workspace--current)
                        :height (frame-pixel-height exwm-workspace--current)))
@@ -161,10 +164,11 @@
           (make-instance 'xcb:ConfigureWindow
                          :window (frame-parameter exwm--floating-frame
                                                   'exwm-outer-id)
-                         :value-mask (logior xcb:ConfigWindow:X
-                                             xcb:ConfigWindow:Y
-                                             xcb:ConfigWindow:Width
-                                             xcb:ConfigWindow:Height)
+                         :value-mask (eval-when-compile
+                                       (logior xcb:ConfigWindow:X
+                                               xcb:ConfigWindow:Y
+                                               xcb:ConfigWindow:Width
+                                               xcb:ConfigWindow:Height))
                          :x (elt exwm--floating-frame-geometry 0)
                          :y (elt exwm--floating-frame-geometry 1)
                          :width (elt exwm--floating-frame-geometry 2)
@@ -194,10 +198,11 @@
       (xcb:+request exwm--connection
           (make-instance 'xcb:ConfigureWindow
                          :window id
-                         :value-mask (logior xcb:ConfigWindow:X
-                                             xcb:ConfigWindow:Y
-                                             xcb:ConfigWindow:Width
-                                             xcb:ConfigWindow:Height)
+                         :value-mask (eval-when-compile
+                                       (logior xcb:ConfigWindow:X
+                                               xcb:ConfigWindow:Y
+                                               xcb:ConfigWindow:Width
+                                               xcb:ConfigWindow:Height))
                          :x x :y y
                          :width width
                          :height height))
diff --git a/exwm-manage.el b/exwm-manage.el
index d83fc447d632..ae707f73ee5b 100644
--- a/exwm-manage.el
+++ b/exwm-manage.el
@@ -124,8 +124,9 @@ corresponding buffer.")
             (xcb:+request exwm--connection
                 (make-instance 'xcb:ConfigureWindow
                                :window id
-                               :value-mask (logior xcb:ConfigWindow:X
-                                                   xcb:ConfigWindow:Y)
+                               :value-mask (eval-when-compile
+                                             (logior xcb:ConfigWindow:X
+                                                     xcb:ConfigWindow:Y))
                                :x (/ (- (frame-pixel-width
                                          exwm-workspace--current)
                                         width)
diff --git a/exwm-randr.el b/exwm-randr.el
index fc8477d2aa27..26d15dcb7d99 100644
--- a/exwm-randr.el
+++ b/exwm-randr.el
@@ -90,10 +90,11 @@
           (xcb:+request exwm--connection
               (make-instance 'xcb:ConfigureWindow
                              :window (frame-parameter frame 'exwm-outer-id)
-                             :value-mask (logior xcb:ConfigWindow:X
-                                                 xcb:ConfigWindow:Y
-                                                 xcb:ConfigWindow:Width
-                                                 xcb:ConfigWindow:Height)
+                             :value-mask (eval-when-compile
+                                           (logior xcb:ConfigWindow:X
+                                                   xcb:ConfigWindow:Y
+                                                   xcb:ConfigWindow:Width
+                                                   xcb:ConfigWindow:Height))
                              :x x :y y :width width :height height))
           (setq workareas (nconc workareas (list x y width height))
                 viewports (nconc viewports (list x y))))))
@@ -133,11 +134,12 @@
             (make-instance 'xcb:randr:SelectInput
                            :window exwm--root
                            :enable xcb:randr:NotifyMask:ScreenChange
-                           ;; :enable (logior
-                           ;;          xcb:randr:NotifyMask:ScreenChange
-                           ;;          xcb:randr:NotifyMask:OutputChange
-                           ;;          xcb:randr:NotifyMask:OutputProperty
-                           ;;          xcb:randr:NotifyMask:CrtcChange)
+                           ;; :enable (eval-when-compile
+                           ;;           (logior
+                           ;;            xcb:randr:NotifyMask:ScreenChange
+                           ;;            xcb:randr:NotifyMask:OutputChange
+                           ;;            xcb:randr:NotifyMask:OutputProperty
+                           ;;            xcb:randr:NotifyMask:CrtcChange))
                            ))
         (xcb:flush exwm--connection)))))
 
diff --git a/exwm.el b/exwm.el
index d2a0ecf14460..b5d246ed40b8 100644
--- a/exwm.el
+++ b/exwm.el
@@ -5,7 +5,7 @@
 ;; Author: Chris Feng <chris.w.feng@gmail.com>
 ;; Maintainer: Chris Feng <chris.w.feng@gmail.com>
 ;; Version: 0
-;; Package-Requires: ((xelb "0.1"))
+;; Package-Requires: ((xelb "0.3"))
 ;; Keywords: unix
 ;; URL: https://github.com/ch11ng/exwm
 
@@ -74,6 +74,7 @@
 
 ;;; Code:
 
+(require 'server)
 (require 'exwm-core)
 (require 'exwm-workspace)
 (require 'exwm-layout)
@@ -526,14 +527,78 @@
         (exwm-manage--scan)
         (run-hooks 'exwm-init-hook)))))
 
+(defvar exwm-blocking-subrs '(x-file-dialog x-popup-dialog x-select-font)
+  "Subrs (primitives) that would normally block EXWM.")
+
 (defun exwm-enable (&optional undo)
   "Enable/Disable EXWM."
-  (if (eq undo 'undo)
-      (progn (remove-hook 'window-setup-hook #'exwm-init)
-             (remove-hook 'after-make-frame-functions #'exwm-init))
-    (setq frame-resize-pixelwise t)     ;mandatory; before init
-    (add-hook 'window-setup-hook #'exwm-init t)            ;for Emacs
-    (add-hook 'after-make-frame-functions #'exwm-init t))) ;for Emacs Client
+  (pcase undo
+    (`undo                              ;prevent reinitialization
+     (remove-hook 'window-setup-hook #'exwm-init)
+     (remove-hook 'after-make-frame-functions #'exwm-init))
+    (`undo-all                          ;attempt to revert everything
+     (remove-hook 'window-setup-hook #'exwm-init)
+     (remove-hook 'after-make-frame-functions #'exwm-init)
+     (remove-hook 'kill-emacs-hook #'exwm--server-stop)
+     (dolist (i exwm-blocking-subrs)
+       (advice-remove i #'exwm--server-eval-at)))
+    (_                                  ;enable EXWM
+     (setq frame-resize-pixelwise t)    ;mandatory; before init
+     (add-hook 'window-setup-hook #'exwm-init t)          ;for Emacs
+     (add-hook 'after-make-frame-functions #'exwm-init t) ;for Emacs Client
+     (add-hook 'kill-emacs-hook #'exwm--server-stop)
+     (dolist (i exwm-blocking-subrs)
+       (advice-add i :around #'exwm--server-eval-at)))))
+
+(defconst exwm--server-name "server-exwm"
+  "Name of the subordinate Emacs server.")
+(defvar exwm--server-process nil "Process of the subordinate Emacs server.")
+
+(defun exwm--server-stop ()
+  "Stop the subordinate Emacs server."
+  (server-force-delete exwm--server-name)
+  (when exwm--server-process
+    (delete-process exwm--server-process)
+    (setq exwm--server-process nil)))
+
+(defun exwm--server-eval-at (&rest args)
+  "Wrapper of `server-eval-at' used to advice subrs."
+  ;; Start the subordinate Emacs server if it's not alive
+  (unless (server-running-p exwm--server-name)
+    (when exwm--server-process (delete-process exwm--server-process))
+    (setq exwm--server-process
+          (start-process exwm--server-name
+                         nil
+                         (car command-line-args) ;The executable file
+                         "-d" x-display-name
+                         "-Q"
+                         (concat "--daemon=" exwm--server-name)
+                         "--eval"
+                         ;; Create an invisible frame
+                         "(make-frame '((window-system . x) (visibility)))"))
+    (while (not (server-running-p exwm--server-name))
+      (sit-for 0.001)))
+  (server-eval-at
+   exwm--server-name
+   `(progn (select-frame (car (frame-list)))
+           (let ((result ,(nconc (list (make-symbol (subr-name (car args))))
+                                 (cdr args))))
+             (pcase (type-of result)
+               ;; Return the name of a buffer
+               (`buffer (buffer-name result))
+               ;; We blindly convert all font objects to their XLFD names. This
+               ;; might cause problems of course, but it still has a chance to
+               ;; work (whereas directly passing font objects would merely
+               ;; raise errors).
+               ((or `font-entity `font-object `font-spec)
+                (font-xlfd-name result))
+               ;; Passing following types makes little sense
+               ((or `compiled-function `finalizer `frame `hash-table `marker
+                    `overlay `process `window `window-configuration))
+               ;; Passing the name of a subr
+               (`subr (make-symbol (subr-name result)))
+               ;; For other types, return the value as-is.
+               (t result))))))
 
 (defun exwm--ido-buffer-window-other-frame (orig-fun buffer)
   "Wrapper for `ido-buffer-window-other-frame' to exclude invisible windows."