mirror of
https://github.com/ch11ng/exwm.git
synced 2024-11-23 19:47:58 +01:00
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.
This commit is contained in:
parent
f685de12d4
commit
5184f0d7c1
7 changed files with 158 additions and 72 deletions
|
@ -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).
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)))))
|
||||
|
||||
|
|
79
exwm.el
79
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."
|
||||
|
|
Loading…
Reference in a new issue