Skip to content

Commit 912ecf5

Browse files
committed
Create exwm-minor-mode
* exwm.el (exwm-minor-mode): New function. (exwm-enable, exwm-disable, exwm-init, exwm-exit): Deprecate in favor of `exwm-minor-mode'. (exwm--init): Rework to signal errors and cleanup in case of errors. (exwm--exit): More thorough cleanup. (exwm--cleanup): New function. (exwm--on-SelectionClear, exwm--confirm-kill-emacs): : Use `exwm--exit'. (exwm--terminal-x-p, exwm--find-any-x-frame) (exwm--init-on-window-setup-hook) (exwm--init-on-after-make-frame, exwm--cleanup): New functions. (exwm--wmsn-acquire): Signal error instead of using `user-error'.
1 parent 10bd122 commit 912ecf5

File tree

2 files changed

+132
-44
lines changed

2 files changed

+132
-44
lines changed

exwm-config.el

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
([?\C-d] . [delete])
7474
([?\C-k] . [S-end delete]))))
7575
;; Enable EXWM
76-
(exwm-enable)
76+
(exwm-minor-mode +1)
7777
;; Configure Ido
7878
(exwm-config-ido)
7979
;; Other configurations

exwm.el

Lines changed: 131 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
(require 'exwm-floating)
7272
(require 'exwm-manage)
7373
(require 'exwm-input)
74+
(require 'seq)
7475

7576
(defgroup exwm nil
7677
"Emacs X Window Manager."
@@ -110,6 +111,10 @@
110111

111112
(defvar exwm--server-process nil "Process of the subordinate Emacs server.")
112113

114+
(define-error 'exwm-frame-not-x "Frame not running under X environment" 'error)
115+
(define-error 'exwm-already-running "EXWM already running" 'error)
116+
(define-error 'exwm-other-wm "Other window manager running" 'error)
117+
113118
(defun exwm-reset ()
114119
"Reset the state of the selected window (non-fullscreen, line-mode, etc)."
115120
(interactive)
@@ -603,7 +608,7 @@
603608
selection (slot-value obj 'selection))
604609
(when (and (eq owner exwm--wmsn-window)
605610
(eq selection xcb:Atom:WM_S0))
606-
(exwm-exit))))
611+
(exwm--exit))))
607612

608613
(defun exwm--init-icccm-ewmh ()
609614
"Initialize ICCCM/EWMH support."
@@ -761,7 +766,7 @@ manager. If t, replace it, if nil, abort and ask the user if `ask'."
761766
(when (eq replace 'ask)
762767
(setq replace (yes-or-no-p "Replace existing window manager? ")))
763768
(when (not replace)
764-
(user-error "Other window manager detected")))
769+
(signal 'exwm-other-wm "Other window manager detected")))
765770
(let ((new-owner (xcb:generate-id exwm--connection)))
766771
(xcb:+request exwm--connection
767772
(make-instance 'xcb:CreateWindow
@@ -824,23 +829,61 @@ manager. If t, replace it, if nil, abort and ask the user if `ask'."
824829
(setq exwm--wmsn-window new-owner))))
825830

826831
;;;###autoload
827-
(cl-defun exwm-init (&optional frame)
832+
(define-minor-mode exwm-minor-mode
833+
"Minor mode to enable or disable EXWM.
834+
835+
EXWM (Emacs X Window Manager) is a full-featured tiling X window manager
836+
for Emacs built on top of XELB.
837+
838+
If called interactively, enable EXWM minor mode if ARG is positive, and
839+
disable it if ARG is zero or negative. If called from Lisp, also
840+
enable the mode if ARG is omitted or nil, and toggle it if ARG is
841+
‘toggle’; disable the mode otherwise.
842+
843+
If no X display can be found, EXWM will be started as soon as the first X
844+
frame is created."
845+
:global t
846+
:group 'exwm
847+
(if exwm-minor-mode
848+
;; Up
849+
(if exwm--connection
850+
(exwm--log "EXWM already running")
851+
(let ((frame (exwm--find-any-x-frame)))
852+
(if frame
853+
(exwm--init frame) ; initialize right away if any X frame exists.
854+
(exwm--enable)))) ; will initialize as soon as there's an X frame.
855+
;; Down
856+
(if exwm--connection
857+
(exwm--exit)
858+
(exwm--disable))))
859+
860+
(defun exwm--init-on-window-setup-hook ()
861+
"Try to start EXWM on selected frame."
862+
(exwm--init-on-after-make-frame (selected-frame)))
863+
864+
(defun exwm--init-on-after-make-frame (frame)
865+
"Try to start EXWM if FRAME's window-system is X."
866+
(condition-case _
867+
(exwm--init frame)
868+
;; Ignore non X frames.
869+
(exwm-frame-not-x)))
870+
871+
(defun exwm--init (&optional frame)
828872
"Initialize EXWM."
829873
(interactive)
830874
(exwm--log "%s" frame)
831875
(if frame
832-
;; The frame might not be selected if it's created by emacslicnet.
876+
;; The frame might not be selected if it's created by emacsclient.
833877
(select-frame-set-input-focus frame)
834878
(setq frame (selected-frame)))
835879
(when (not (eq 'x (framep frame)))
836-
(message "[EXWM] Not running under X environment")
837-
(cl-return-from exwm-init))
880+
(signal 'exwm-frame-not-x frame))
838881
(when exwm--connection
839882
(exwm--log "EXWM already running")
840-
(cl-return-from exwm-init))
883+
(signal 'exwm-already-running frame))
841884
(condition-case err
842885
(progn
843-
(exwm-enable 'undo) ;never initialize again
886+
(exwm--disable) ;never initialize again
844887
(setq exwm--connection (xcb:connect))
845888
(set-process-query-on-exit-flag (slot-value exwm--connection 'process)
846889
nil) ;prevent query message on exit
@@ -860,9 +903,16 @@ manager. If t, replace it, if nil, abort and ask the user if `ask'."
860903
:event-mask
861904
xcb:EventMask:SubstructureRedirect))
862905
(error "Other window manager is running"))
906+
; Mandatory; before init.
907+
(setq frame-resize-pixelwise t
908+
window-resize-pixelwise t)
863909
;; Disable some features not working well with EXWM
864910
(setq use-dialog-box nil
865911
confirm-kill-emacs #'exwm--confirm-kill-emacs)
912+
;; Manage the subordinate Emacs server.
913+
(add-hook 'kill-emacs-hook #'exwm--server-stop)
914+
(dolist (i exwm-blocking-subrs)
915+
(advice-add i :around #'exwm--server-eval-at))
866916
(exwm--lock)
867917
(exwm--init-icccm-ewmh)
868918
(exwm-layout--init)
@@ -876,59 +926,59 @@ manager. If t, replace it, if nil, abort and ask the user if `ask'."
876926
(run-hooks 'exwm-init-hook)
877927
;; Manage existing windows
878928
(exwm-manage--scan))
879-
(user-error)
929+
(exwm-other-wm
930+
(exwm--cleanup)
931+
(signal (car err) (cdr err)))
880932
((quit error)
881-
(exwm-exit)
933+
(exwm--exit)
882934
;; Rethrow error
883935
(warn "[EXWM] EXWM fails to start (%s: %s)" (car err) (cdr err)))))
884936

885-
886-
;;;###autoload
887-
(defun exwm-exit ()
937+
(defun exwm--exit ()
888938
"Exit EXWM."
889939
(interactive)
890940
(exwm--log)
891941
(run-hooks 'exwm-exit-hook)
942+
;; Revert disabled features.
892943
(setq confirm-kill-emacs nil)
944+
(remove-hook 'kill-emacs-hook #'exwm--server-stop)
945+
(dolist (i exwm-blocking-subrs)
946+
(advice-remove i #'exwm--server-eval-at))
893947
;; Exit modules.
894948
(exwm-input--exit)
895949
(exwm-manage--exit)
896950
(exwm-workspace--exit)
897951
(exwm-floating--exit)
898952
(exwm-layout--exit)
953+
(exwm--cleanup))
954+
955+
(defun exwm--cleanup ()
956+
"Cleanup EXWM variables."
899957
(when exwm--connection
900958
(xcb:flush exwm--connection)
901959
(xcb:disconnect exwm--connection))
902-
(setq exwm--connection nil))
960+
(setq exwm--connection nil)
961+
(setq exwm--root nil))
903962

904-
;;;###autoload
905-
(defun exwm-enable (&optional undo)
906-
"Enable/Disable EXWM."
907-
(exwm--log "%s" undo)
908-
(pcase undo
909-
(`undo ;prevent reinitialization
910-
(remove-hook 'window-setup-hook #'exwm-init)
911-
(remove-hook 'after-make-frame-functions #'exwm-init))
912-
(`undo-all ;attempt to revert everything
913-
(remove-hook 'window-setup-hook #'exwm-init)
914-
(remove-hook 'after-make-frame-functions #'exwm-init)
915-
(remove-hook 'kill-emacs-hook #'exwm--server-stop)
916-
(dolist (i exwm-blocking-subrs)
917-
(advice-remove i #'exwm--server-eval-at)))
918-
(_ ;enable EXWM
919-
(setq frame-resize-pixelwise t ;mandatory; before init
920-
window-resize-pixelwise t)
921-
;; Ignore unrecognized command line arguments. This can be helpful
922-
;; when EXWM is launched by some session manager.
923-
(push #'vector command-line-functions)
924-
;; In case EXWM is to be started from a graphical Emacs instance.
925-
(add-hook 'window-setup-hook #'exwm-init t)
926-
;; In case EXWM is to be started with emacsclient.
927-
(add-hook 'after-make-frame-functions #'exwm-init t)
928-
;; Manage the subordinate Emacs server.
929-
(add-hook 'kill-emacs-hook #'exwm--server-stop)
930-
(dolist (i exwm-blocking-subrs)
931-
(advice-add i :around #'exwm--server-eval-at)))))
963+
(defun exwm--enable ()
964+
"Enable EXWM.
965+
Register functions for EXWM to be initialized as soon as Emacs is and there is
966+
an X display available."
967+
(exwm--log)
968+
;; Ignore unrecognized command line arguments. This can be helpful
969+
;; when EXWM is launched by some session manager.
970+
(push #'vector command-line-functions)
971+
;; In case EXWM is to be started from a graphical Emacs instance.
972+
(add-hook 'window-setup-hook #'exwm--init-on-window-setup-hook t)
973+
;; In case EXWM is to be started with emacsclient.
974+
(add-hook 'after-make-frame-functions #'exwm--init-on-after-make-frame t))
975+
976+
(defun exwm--disable ()
977+
"Disable EXWM.
978+
See `exwm--enable`."
979+
(exwm--log)
980+
(remove-hook 'window-setup-hook #'exwm--init-on-window-setup-hook)
981+
(remove-hook 'after-make-frame-functions #'exwm--init-on-after-make-frame))
932982

933983
(defun exwm--server-stop ()
934984
"Stop the subordinate Emacs server."
@@ -1008,10 +1058,48 @@ manager. If t, replace it, if nil, abort and ask the user if `ask'."
10081058
(run-hooks 'kill-emacs-hook)
10091059
(setq kill-emacs-hook nil))
10101060
;; Exit each module, destroying all resources created by this connection.
1011-
(exwm-exit)
1061+
(exwm--exit)
10121062
;; Set the return value.
10131063
t))
10141064

1065+
(defun exwm--terminal-x-p (terminal)
1066+
"Check whether TERMINAL is an X terminal."
1067+
(eq 'x (terminal-live-p terminal)))
1068+
1069+
(defun exwm--find-any-x-frame ()
1070+
"Find a frame whose terminal is an X display.
1071+
Selected frame is checked first."
1072+
(let* ((terminals (cons (frame-terminal (selected-frame))
1073+
(terminal-list)))
1074+
(found-terminal (seq-find 'exwm--terminal-x-p terminals)))
1075+
(when found-terminal
1076+
(car (frames-on-display-list found-terminal)))))
1077+
1078+
1079+
;;; Obsolete:
1080+
1081+
;;;###autoload
1082+
(defun exwm-enable (&optional undo)
1083+
"Enable/Disable EXWM."
1084+
(exwm--log "%s" undo)
1085+
(pcase undo
1086+
(`undo (exwm--disable))
1087+
(_ (exwm--enable))))
1088+
(make-obsolete 'exwm-enable
1089+
"Please use `exwm-minor-mode` instead"
1090+
"exwm-0.24")
1091+
1092+
(defalias 'exwm-init 'exwm--init)
1093+
(make-obsolete 'exwm-init
1094+
"Please use `exwm-minor-mode` instead"
1095+
"exwm-0.24")
1096+
1097+
;;;###autoload
1098+
(defalias 'exwm-exit 'exwm--exit)
1099+
(make-obsolete 'exwm-exit
1100+
"Please use `exwm-minor-mode` instead"
1101+
"exwm-0.24")
1102+
10151103

10161104

10171105
(provide 'exwm)

0 commit comments

Comments
 (0)