71
71
(require 'exwm-floating )
72
72
(require 'exwm-manage )
73
73
(require 'exwm-input )
74
+ (require 'seq )
74
75
75
76
(defgroup exwm nil
76
77
" Emacs X Window Manager."
110
111
111
112
(defvar exwm--server-process nil " Process of the subordinate Emacs server." )
112
113
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
+
113
118
(defun exwm-reset ()
114
119
" Reset the state of the selected window (non-fullscreen, line-mode, etc)."
115
120
(interactive )
603
608
selection (slot-value obj 'selection ))
604
609
(when (and (eq owner exwm--wmsn-window)
605
610
(eq selection xcb:Atom:WM_S0))
606
- (exwm-exit))))
611
+ (exwm-- exit))))
607
612
608
613
(defun exwm--init-icccm-ewmh ()
609
614
" Initialize ICCCM/EWMH support."
@@ -761,7 +766,7 @@ manager. If t, replace it, if nil, abort and ask the user if `ask'."
761
766
(when (eq replace 'ask )
762
767
(setq replace (yes-or-no-p " Replace existing window manager? " )))
763
768
(when (not replace)
764
- (user-error " Other window manager detected" )))
769
+ (signal 'exwm-other-wm " Other window manager detected" )))
765
770
(let ((new-owner (xcb:generate-id exwm--connection)))
766
771
(xcb:+request exwm--connection
767
772
(make-instance 'xcb:CreateWindow
@@ -824,23 +829,61 @@ manager. If t, replace it, if nil, abort and ask the user if `ask'."
824
829
(setq exwm--wmsn-window new-owner))))
825
830
826
831
;;;### 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 )
828
872
" Initialize EXWM."
829
873
(interactive )
830
874
(exwm--log " %s" frame)
831
875
(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 .
833
877
(select-frame-set-input-focus frame)
834
878
(setq frame (selected-frame )))
835
879
(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))
838
881
(when exwm--connection
839
882
(exwm--log " EXWM already running" )
840
- (cl-return-from exwm-init ))
883
+ (signal ' exwm-already-running frame ))
841
884
(condition-case err
842
885
(progn
843
- (exwm-enable 'undo ) ; never initialize again
886
+ (exwm--disable ) ; never initialize again
844
887
(setq exwm--connection (xcb:connect))
845
888
(set-process-query-on-exit-flag (slot-value exwm--connection 'process )
846
889
nil ) ; prevent query message on exit
@@ -860,9 +903,16 @@ manager. If t, replace it, if nil, abort and ask the user if `ask'."
860
903
:event-mask
861
904
xcb:EventMask:SubstructureRedirect))
862
905
(error " Other window manager is running " ))
906
+ ; Mandatory; before init.
907
+ (setq frame-resize-pixelwise t
908
+ window-resize-pixelwise t )
863
909
; ; Disable some features not working well with EXWM
864
910
(setq use-dialog-box nil
865
911
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 ))
866
916
(exwm--lock)
867
917
(exwm--init-icccm-ewmh)
868
918
(exwm-layout--init)
@@ -876,59 +926,59 @@ manager. If t, replace it, if nil, abort and ask the user if `ask'."
876
926
(run-hooks 'exwm-init-hook )
877
927
; ; Manage existing windows
878
928
(exwm-manage--scan))
879
- (user-error )
929
+ (exwm-other-wm
930
+ (exwm--cleanup)
931
+ (signal (car err) (cdr err)))
880
932
((quit error )
881
- (exwm-exit)
933
+ (exwm-- exit)
882
934
; ; Rethrow error
883
935
(warn " [EXWM] EXWM fails to start (%s: %s)" (car err) (cdr err)))))
884
936
885
-
886
- ;;;### autoload
887
- (defun exwm-exit ()
937
+ (defun exwm--exit ()
888
938
" Exit EXWM."
889
939
(interactive )
890
940
(exwm--log)
891
941
(run-hooks 'exwm-exit-hook )
942
+ ; ; Revert disabled features.
892
943
(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 ))
893
947
; ; Exit modules.
894
948
(exwm-input--exit)
895
949
(exwm-manage--exit)
896
950
(exwm-workspace--exit)
897
951
(exwm-floating--exit)
898
952
(exwm-layout--exit)
953
+ (exwm--cleanup))
954
+
955
+ (defun exwm--cleanup ()
956
+ " Cleanup EXWM variables."
899
957
(when exwm--connection
900
958
(xcb:flush exwm--connection)
901
959
(xcb:disconnect exwm--connection))
902
- (setq exwm--connection nil ))
960
+ (setq exwm--connection nil )
961
+ (setq exwm--root nil ))
903
962
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 ))
932
982
933
983
(defun exwm--server-stop ()
934
984
" Stop the subordinate Emacs server."
@@ -1008,10 +1058,48 @@ manager. If t, replace it, if nil, abort and ask the user if `ask'."
1008
1058
(run-hooks 'kill-emacs-hook )
1009
1059
(setq kill-emacs-hook nil ))
1010
1060
; ; Exit each module, destroying all resources created by this connection.
1011
- (exwm-exit)
1061
+ (exwm-- exit)
1012
1062
; ; Set the return value.
1013
1063
t ))
1014
1064
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
+
1015
1103
1016
1104
1017
1105
(provide 'exwm )
0 commit comments