Add customization settings

; Also fix documentations.
This commit is contained in:
Chris Feng 2018-02-19 00:04:27 +08:00
parent 7823eb988c
commit d22e6740d7
11 changed files with 500 additions and 377 deletions

View file

@ -21,7 +21,7 @@
;;; Commentary: ;;; Commentary:
;; This module is obsolete since EXWM now supports third-porty compositors. ;; This module is obsolete since EXWM now supports third-party compositors.
;;; Code: ;;; Code:

View file

@ -35,6 +35,32 @@
(eval-and-compile (eval-and-compile
(defvar exwm-debug-on nil "Non-nil to turn on debug for EXWM.")) (defvar exwm-debug-on nil "Non-nil to turn on debug for EXWM."))
(defvar exwm--connection nil "X connection.")
(defvar exwm--guide-window nil
"An X window separating workspaces and X windows.")
(defvar exwm--id-buffer-alist nil "Alist of (<X window ID> . <Emacs buffer>).")
(defvar exwm--root nil "Root window.")
(defvar exwm-input--global-prefix-keys)
(defvar exwm-input--simulation-prefix-keys)
(defvar exwm-input-line-mode-passthrough)
(defvar exwm-input-prefix-keys)
(declare-function exwm-input--fake-key "exwm-input.el" (event))
(declare-function exwm-input--on-KeyPress-line-mode "exwm-input.el"
(key-press raw-data))
(declare-function exwm-floating-hide "exwm-floating.el")
(declare-function exwm-floating-toggle-floating "exwm-floating.el")
(declare-function exwm-input-release-keyboard "exwm-input.el")
(declare-function exwm-input-send-next-key "exwm-input.el" (times))
(declare-function exwm-layout-set-fullscreen "exwm-layout.el" (&optional id))
(declare-function exwm-layout-toggle-mode-line "exwm-layout.el")
(declare-function exwm-manage--kill-buffer-query-function "exwm-manage.el")
(declare-function exwm-workspace-move-window "exwm-workspace.el"
(frame-or-index &optional id))
(defmacro exwm--log (format-string &rest args) (defmacro exwm--log (format-string &rest args)
"Print debug message." "Print debug message."
(when exwm-debug-on (when exwm-debug-on
@ -43,12 +69,6 @@
(defmacro exwm--debug (&rest forms) (defmacro exwm--debug (&rest forms)
(when exwm-debug-on `(progn ,@forms))) (when exwm-debug-on `(progn ,@forms)))
(defvar exwm--connection nil "X connection.")
(defvar exwm--root nil "Root window.")
(defvar exwm--id-buffer-alist nil "Alist of (<X window ID> . <Emacs buffer>).")
(defvar exwm--guide-window nil
"An X window separating workspaces and X windows.")
(defsubst exwm--id->buffer (id) (defsubst exwm--id->buffer (id)
"X window ID => Emacs buffer." "X window ID => Emacs buffer."
(cdr (assoc id exwm--id-buffer-alist))) (cdr (assoc id exwm--id-buffer-alist)))
@ -108,15 +128,6 @@ least SECS seconds later."
xcb:EventMask:EnterWindow 0)) xcb:EventMask:EnterWindow 0))
"Event mask set on all managed windows.") "Event mask set on all managed windows.")
(defvar exwm-input-line-mode-passthrough)
(defvar exwm-input--global-prefix-keys)
(defvar exwm-input-prefix-keys)
(defvar exwm-input--simulation-prefix-keys)
(declare-function exwm-input--fake-key "exwm-input.el" (event))
(declare-function exwm-input--on-KeyPress-line-mode "exwm-input.el"
(key-press raw-data))
;; Internal variables ;; Internal variables
(defvar-local exwm--id nil) ;window ID (defvar-local exwm--id nil) ;window ID
(defvar-local exwm--frame nil) ;workspace frame (defvar-local exwm--frame nil) ;workspace frame
@ -154,15 +165,6 @@ least SECS seconds later."
;; _MOTIF_WM_HINTS ;; _MOTIF_WM_HINTS
(defvar-local exwm--mwm-hints-decorations t) (defvar-local exwm--mwm-hints-decorations t)
(declare-function exwm-floating-hide "exwm-floating.el")
(declare-function exwm-floating-toggle-floating "exwm-floating.el")
(declare-function exwm-input-release-keyboard "exwm-input.el")
(declare-function exwm-input-send-next-key "exwm-input.el" (times))
(declare-function exwm-layout-set-fullscreen "exwm-layout.el" (&optional id))
(declare-function exwm-layout-toggle-mode-line "exwm-layout.el")
(declare-function exwm-workspace-move-window "exwm-workspace.el"
(frame-or-index &optional id))
(defvar exwm-mode-map (defvar exwm-mode-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(define-key map "\C-c\C-f" #'exwm-layout-set-fullscreen) (define-key map "\C-c\C-f" #'exwm-layout-set-fullscreen)
@ -264,8 +266,6 @@ least SECS seconds later."
(/= ,i exwm-workspace-current-index)]) (/= ,i exwm-workspace-current-index)])
(number-sequence 0 (1- (exwm-workspace--count)))))))) (number-sequence 0 (1- (exwm-workspace--count))))))))
(declare-function exwm-manage--kill-buffer-query-function "exwm-manage.el")
(define-derived-mode exwm-mode nil "EXWM" (define-derived-mode exwm-mode nil "EXWM"
"Major mode for managing X windows. "Major mode for managing X windows.

View file

@ -29,22 +29,35 @@
(require 'xcb-cursor) (require 'xcb-cursor)
(require 'exwm-core) (require 'exwm-core)
(defvar exwm-floating-border-width 1 "Border width of the floating window.") (defgroup exwm-floating nil
(defvar exwm-floating-border-color "navy" "Floating."
"Border color of the floating window.") :version "25.3"
(defvar exwm-floating--border-pixel nil :group 'exwm)
"Border pixel drawn around floating X windows.")
(defcustom exwm-floating-setup-hook nil
"Normal hook run when an X window has been made floating, in the
context of the corresponding buffer."
:type 'hook)
(defcustom exwm-floating-exit-hook nil
"Normal hook run when an X window has exited floating state, in the
context of the corresponding buffer."
:type 'hook)
(defcustom exwm-floating-border-color "navy"
"Border color of floating windows."
:type 'color)
(defcustom exwm-floating-border-width 1
"Border width of floating windows."
:type 'integer)
(defvar exwm-floating--border-colormap nil (defvar exwm-floating--border-colormap nil
"Colormap used by the border pixel. "Colormap used by the border pixel.
This is also used by X window containers.") This is also used by X window containers.")
(defvar exwm-floating--border-pixel nil
(defvar exwm-floating-setup-hook nil "Border pixel drawn around floating X windows.")
"Normal hook run when an X window has been made floating, in the
context of the corresponding buffer.")
(defvar exwm-floating-exit-hook nil
"Normal hook run when an X window has exited floating state, in the
context of the corresponding buffer.")
;; Cursors for moving/resizing a window ;; Cursors for moving/resizing a window
(defvar exwm-floating--cursor-move nil) (defvar exwm-floating--cursor-move nil)
@ -57,6 +70,18 @@ context of the corresponding buffer.")
(defvar exwm-floating--cursor-bottom-left nil) (defvar exwm-floating--cursor-bottom-left nil)
(defvar exwm-floating--cursor-left nil) (defvar exwm-floating--cursor-left nil)
(defvar exwm-floating--moveresize-calculate nil
"Calculate move/resize parameters [buffer event-mask x y width height].")
(defvar exwm-workspace--current)
(defvar exwm-workspace--workareas)
(declare-function exwm-layout--hide "exwm-layout.el" (id))
(declare-function exwm-layout--iconic-state-p "exwm-layout.el" (&optional id))
(declare-function exwm-layout--refresh "exwm-layout.el" ())
(declare-function exwm-layout--show "exwm-layout.el" (id &optional window))
(declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el")
(declare-function exwm-workspace--position "exwm-workspace.el" (frame))
(defun exwm-floating--set-allowed-actions (id tilling) (defun exwm-floating--set-allowed-actions (id tilling)
"Set _NET_WM_ALLOWED_ACTIONS." "Set _NET_WM_ALLOWED_ACTIONS."
(xcb:+request exwm--connection (xcb:+request exwm--connection
@ -74,16 +99,6 @@ context of the corresponding buffer.")
xcb:Atom:_NET_WM_ACTION_CHANGE_DESKTOP xcb:Atom:_NET_WM_ACTION_CHANGE_DESKTOP
xcb:Atom:_NET_WM_ACTION_CLOSE))))) xcb:Atom:_NET_WM_ACTION_CLOSE)))))
(defvar exwm-workspace--current)
(defvar exwm-workspace--workareas)
(declare-function exwm-layout--refresh "exwm-layout.el" ())
(declare-function exwm-layout--show "exwm-layout.el" (id &optional window))
(declare-function exwm-layout--hide "exwm-layout.el" (id))
(declare-function exwm-layout--iconic-state-p "exwm-layout.el" (&optional id))
(declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el")
(declare-function exwm-workspace--position "exwm-workspace.el" (frame))
(defun exwm-floating--set-floating (id) (defun exwm-floating--set-floating (id)
"Make window ID floating." "Make window ID floating."
(let ((window (get-buffer-window (exwm--id->buffer id)))) (let ((window (get-buffer-window (exwm--id->buffer id))))
@ -331,16 +346,16 @@ context of the corresponding buffer.")
(run-hooks 'exwm-floating-exit-hook))) (run-hooks 'exwm-floating-exit-hook)))
;;;###autoload ;;;###autoload
(defun exwm-floating-toggle-floating () (cl-defun exwm-floating-toggle-floating ()
"Toggle the current window between floating and non-floating states." "Toggle the current window between floating and non-floating states."
(interactive) (interactive)
(unless (derived-mode-p 'exwm-mode)
(cl-return-from 'exwm-floating-toggle-floating))
(with-current-buffer (window-buffer) (with-current-buffer (window-buffer)
(if exwm--floating-frame (if exwm--floating-frame
(exwm-floating--unset-floating exwm--id) (exwm-floating--unset-floating exwm--id)
(exwm-floating--set-floating exwm--id)))) (exwm-floating--set-floating exwm--id))))
(declare-function exwm-layout--set-state "exwm-layout.el" (id state))
;;;###autoload ;;;###autoload
(defun exwm-floating-hide () (defun exwm-floating-hide ()
"Hide the current floating X window (which would show again when selected)." "Hide the current floating X window (which would show again when selected)."
@ -350,14 +365,6 @@ context of the corresponding buffer.")
(exwm-layout--hide exwm--id) (exwm-layout--hide exwm--id)
(select-frame-set-input-focus exwm-workspace--current))) (select-frame-set-input-focus exwm-workspace--current)))
(define-obsolete-function-alias 'exwm-floating-hide-mode-line
'exwm-layout-hide-mode-line "25.1" "Hide mode-line of a floating frame.")
(define-obsolete-function-alias 'exwm-floating-show-mode-line
'exwm-layout-show-mode-line "25.1" "Show mode-line of a floating frame.")
(defvar exwm-floating--moveresize-calculate nil
"Calculate move/resize parameters [buffer event-mask x y width height].")
(defun exwm-floating--start-moveresize (id &optional type) (defun exwm-floating--start-moveresize (id &optional type)
"Start move/resize." "Start move/resize."
(let ((buffer-or-id (or (exwm--id->buffer id) id)) (let ((buffer-or-id (or (exwm--id->buffer id) id))

View file

@ -38,32 +38,119 @@
(require 'xcb-keysyms) (require 'xcb-keysyms)
(require 'exwm-core) (require 'exwm-core)
(defvar exwm-input-move-event 's-down-mouse-1 (defgroup exwm-input nil
"Emacs event to start moving a window.") "Input."
(defvar exwm-input-resize-event 's-down-mouse-3 :version "25.3"
"Emacs event to start resizing a window.") :group 'exwm)
(defvar exwm-input--timestamp-window nil) (defcustom exwm-input-prefix-keys
(defvar exwm-input--timestamp-atom nil) '(?\C-c ?\C-x ?\C-u ?\C-h ?\M-x ?\M-` ?\M-& ?\M-:)
(defvar exwm-input--timestamp-callback nil) "List of prefix keys EXWM should forward to Emacs when in line-mode."
:type '(repeat key-sequence)
:get (lambda (symbol)
(mapcar #'vector (default-value symbol)))
:set (lambda (symbol value)
(set symbol (mapcar (lambda (i)
(if (sequencep i)
(aref i 0)
i))
value))))
(defvar exwm-workspace--current) (defcustom exwm-input-move-event 's-down-mouse-1
(defvar exwm-workspace--switch-history-outdated) "Emacs event to start moving a window."
(defvar exwm-workspace-current-index) :type 'key-sequence
(defvar exwm-workspace--minibuffer) :get (lambda (symbol)
(defvar exwm-workspace--list) (let ((value (default-value symbol)))
(if (mouse-event-p value)
value
(vector value))))
:set (lambda (symbol value)
(set symbol (if (sequencep value)
(aref value 0)
value))))
(defcustom exwm-input-resize-event 's-down-mouse-3
"Emacs event to start resizing a window."
:type 'key-sequence
:get (lambda (symbol)
(let ((value (default-value symbol)))
(if (mouse-event-p value)
value
(vector value))))
:set (lambda (symbol value)
(set symbol (if (sequencep value)
(aref value 0)
value))))
(defcustom exwm-input-line-mode-passthrough nil
"Non-nil makes 'line-mode' forwards all events to Emacs."
:type 'boolean)
;; Input focus update requests should be accumulated for a short time
;; interval so that only the last one need to be processed. This not
;; improves the overall performance, but avoids the problem of input
;; focus loop, which is a result of the interaction with Emacs frames.
;;
;; FIXME: The time interval is hard to decide and perhaps machine-dependent.
;; A value too small can cause redundant updates of input focus,
;; and even worse, dead loops. OTOH a large value would bring
;; laggy experience.
(defconst exwm-input--update-focus-interval 0.01
"Time interval (in seconds) for accumulating input focus update requests.")
(defvar exwm-input--during-command nil
"Indicate whether between `pre-command-hook' and `post-command-hook'.")
(defvar exwm-input--global-keys nil "Global key bindings.") (defvar exwm-input--global-keys nil "Global key bindings.")
(defvar exwm-input--global-prefix-keys nil (defvar exwm-input--global-prefix-keys nil
"List of prefix keys of global key bindings.") "List of prefix keys of global key bindings.")
(defvar exwm-input-prefix-keys
'(?\C-c ?\C-x ?\C-u ?\C-h ?\M-x ?\M-` ?\M-& ?\M-:) (defvar exwm-input--line-mode-cache nil "Cache for incomplete key sequence.")
"List of prefix keys EXWM should forward to Emacs when in line-mode.")
(defvar exwm-input--local-simulation-keys nil
"Whether simulation keys are local.")
(defvar exwm-input--simulation-keys nil "Simulation keys in line-mode.") (defvar exwm-input--simulation-keys nil "Simulation keys in line-mode.")
(defvar exwm-input--simulation-prefix-keys nil (defvar exwm-input--simulation-prefix-keys nil
"List of prefix keys of simulation keys in line-mode.") "List of prefix keys of simulation keys in line-mode.")
(defvar exwm-input--temp-line-mode nil
"Non-nil indicates it's in temporary line-mode for char-mode.")
(defvar exwm-input--timestamp-atom nil)
(defvar exwm-input--timestamp-callback nil)
(defvar exwm-input--timestamp-window nil)
(defvar exwm-input--update-focus-defer-timer nil "Timer for polling the lock.")
(defvar exwm-input--update-focus-lock nil
"Lock for solving input focus update contention.")
(defvar exwm-input--update-focus-timer nil
"Timer for deferring the update of input focus.")
(defvar exwm-input--update-focus-window nil "The (Emacs) window to be focused.
This value should always be overwritten.")
(defvar exwm-workspace--current)
(declare-function exwm-floating--do-moveresize "exwm-floating.el"
(data _synthetic))
(declare-function exwm-floating--start-moveresize "exwm-floating.el"
(id &optional type))
(declare-function exwm-floating--stop-moveresize "exwm-floating.el"
(&rest _args))
(declare-function exwm-layout--iconic-state-p "exwm-layout.el" (&optional id))
(declare-function exwm-layout--show "exwm-layout.el" (id &optional window)) (declare-function exwm-layout--show "exwm-layout.el" (id &optional window))
(declare-function exwm-workspace--client-p "exwm-workspace.el"
(&optional frame))
(declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el")
(declare-function exwm-workspace--workspace-p "exwm-workspace.el" (workspace))
(declare-function exwm-workspace-switch "exwm-workspace.el"
(frame-or-index &optional force))
(defun exwm-input--set-focus (id) (defun exwm-input--set-focus (id)
"Set input focus to window ID in a proper way." "Set input focus to window ID in a proper way."
@ -185,13 +272,6 @@ ARGS are additional arguments to CALLBACK."
(let ((exwm-input--global-prefix-keys nil)) (let ((exwm-input--global-prefix-keys nil))
(exwm-input--update-global-prefix-keys))) (exwm-input--update-global-prefix-keys)))
(declare-function exwm-workspace--client-p "exwm-workspace.el"
(&optional frame))
(defvar exwm-input--update-focus-window nil "The (Emacs) window to be focused.
This value should always be overwritten.")
(defun exwm-input--on-buffer-list-update () (defun exwm-input--on-buffer-list-update ()
"Run in `buffer-list-update-hook' to track input focus." "Run in `buffer-list-update-hook' to track input focus."
(when (and (not (eq this-command #'handle-switch-frame)) (when (and (not (eq this-command #'handle-switch-frame))
@ -205,24 +285,6 @@ This value should always be overwritten.")
(setq exwm-input--update-focus-window (selected-window)) (setq exwm-input--update-focus-window (selected-window))
(exwm-input--update-focus-defer))) (exwm-input--update-focus-defer)))
;; Input focus update requests should be accumulated for a short time
;; interval so that only the last one need to be processed. This not
;; improves the overall performance, but avoids the problem of input
;; focus loop, which is a result of the interaction with Emacs frames.
;;
;; FIXME: The time interval is hard to decide and perhaps machine-dependent.
;; A value too small can cause redundant updates of input focus,
;; and even worse, dead loops. OTOH a large value would bring
;; laggy experience.
(defconst exwm-input--update-focus-interval 0.01
"Time interval (in seconds) for accumulating input focus update requests.")
(defvar exwm-input--update-focus-lock nil
"Lock for solving input focus update contention.")
(defvar exwm-input--update-focus-defer-timer nil "Timer for polling the lock.")
(defvar exwm-input--update-focus-timer nil
"Timer for deferring the update of input focus.")
(defun exwm-input--update-focus-defer () (defun exwm-input--update-focus-defer ()
"Defer updating input focus." "Defer updating input focus."
(when exwm-input--update-focus-defer-timer (when exwm-input--update-focus-defer-timer
@ -240,12 +302,6 @@ This value should always be overwritten.")
#'exwm-input--update-focus-commit #'exwm-input--update-focus-commit
exwm-input--update-focus-window)))) exwm-input--update-focus-window))))
(declare-function exwm-layout--iconic-state-p "exwm-layout.el" (&optional id))
(declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el")
(declare-function exwm-workspace-switch "exwm-workspace.el"
(frame-or-index &optional force))
(declare-function exwm-workspace--workspace-p "exwm-workspace.el" (workspace))
(defun exwm-input--update-focus-commit (window) (defun exwm-input--update-focus-commit (window)
"Commit updating input focus." "Commit updating input focus."
(setq exwm-input--update-focus-lock t) (setq exwm-input--update-focus-lock t)
@ -317,10 +373,6 @@ This value should always be overwritten.")
:window exwm--root :window exwm--root
:data (or id xcb:Window:None)))) :data (or id xcb:Window:None))))
(declare-function exwm-floating--start-moveresize "exwm-floating.el"
(id &optional type))
(declare-function exwm-workspace--position "exwm-workspace.el" (frame))
(defun exwm-input--on-ButtonPress (data _synthetic) (defun exwm-input--on-ButtonPress (data _synthetic)
"Handle ButtonPress event." "Handle ButtonPress event."
(let ((obj (make-instance 'xcb:ButtonPress)) (let ((obj (make-instance 'xcb:ButtonPress))
@ -419,7 +471,10 @@ This value should always be overwritten.")
;;;###autoload ;;;###autoload
(defun exwm-input-set-key (key command) (defun exwm-input-set-key (key command)
"Set a global key binding." "Set a global key binding.
The new key binding only takes effect in real time when this command is
called interactively. Only invoke it non-interactively in configuration."
(interactive "KSet key globally: \nCSet key %s to command: ") (interactive "KSet key globally: \nCSet key %s to command: ")
(global-set-key key command) (global-set-key key command)
(cl-pushnew key exwm-input--global-keys) (cl-pushnew key exwm-input--global-keys)
@ -437,22 +492,6 @@ This value should always be overwritten.")
(setq unread-command-events (setq unread-command-events
(append unread-command-events `((t . ,event))))))) (append unread-command-events `((t . ,event)))))))
(defvar exwm-input-command-whitelist nil
"A list of commands that when active all keys should be forwarded to Emacs.")
(make-obsolete-variable 'exwm-input-command-whitelist
"This variable can be safely removed." "25.1")
(defvar exwm-input--during-command nil
"Indicate whether between `pre-command-hook' and `post-command-hook'.")
(defvar exwm-input-line-mode-passthrough nil
"Non-nil makes 'line-mode' forwards all events to Emacs.")
(defvar exwm-input--line-mode-cache nil "Cache for incomplete key sequence.")
(defvar exwm-input--temp-line-mode nil
"Non-nil indicates it's in temporary line-mode for char-mode.")
(cl-defun exwm-input--translate (key) (cl-defun exwm-input--translate (key)
(let (translation) (let (translation)
(dolist (map (list input-decode-map (dolist (map (list input-decode-map
@ -606,7 +645,8 @@ This value should always be overwritten.")
;;;###autoload ;;;###autoload
(defun exwm-input-grab-keyboard (&optional id) (defun exwm-input-grab-keyboard (&optional id)
"Switch to line-mode." "Switch to line-mode."
(interactive (list (exwm--buffer->id (window-buffer)))) (interactive (list (when (derived-mode-p 'exwm-mode)
(exwm--buffer->id (window-buffer)))))
(when id (when id
(with-current-buffer (exwm--id->buffer id) (with-current-buffer (exwm--id->buffer id)
(exwm-input--grab-keyboard id) (exwm-input--grab-keyboard id)
@ -617,7 +657,8 @@ This value should always be overwritten.")
;;;###autoload ;;;###autoload
(defun exwm-input-release-keyboard (&optional id) (defun exwm-input-release-keyboard (&optional id)
"Switch to char-mode." "Switch to char-mode."
(interactive (list (exwm--buffer->id (window-buffer)))) (interactive (list (when (derived-mode-p 'exwm-mode)
(exwm--buffer->id (window-buffer)))))
(when id (when id
(with-current-buffer (exwm--id->buffer id) (with-current-buffer (exwm--id->buffer id)
(exwm-input--release-keyboard id) (exwm-input--release-keyboard id)
@ -628,7 +669,8 @@ This value should always be overwritten.")
;;;###autoload ;;;###autoload
(defun exwm-input-toggle-keyboard (&optional id) (defun exwm-input-toggle-keyboard (&optional id)
"Toggle between 'line-mode' and 'char-mode'." "Toggle between 'line-mode' and 'char-mode'."
(interactive (list (exwm--buffer->id (window-buffer)))) (interactive (list (when (derived-mode-p 'exwm-mode)
(exwm--buffer->id (window-buffer)))))
(when id (when id
(with-current-buffer (exwm--id->buffer id) (with-current-buffer (exwm--id->buffer id)
(if exwm--keyboard-grabbed (if exwm--keyboard-grabbed
@ -664,9 +706,14 @@ This value should always be overwritten.")
(xcb:flush exwm--connection))) (xcb:flush exwm--connection)))
;;;###autoload ;;;###autoload
(defun exwm-input-send-next-key (times) (cl-defun exwm-input-send-next-key (times)
"Send next key to client window." "Send next key to client window.
EXWM will prompt for the key to send. This command can be prefixed to send
multiple keys."
(interactive "p") (interactive "p")
(unless (derived-mode-p 'exwm-mode)
(cl-return-from 'exwm-input-send-next-key))
(when (> times 12) (setq times 12)) (when (> times 12) (setq times 12))
(let (key keys) (let (key keys)
(dotimes (i times) (dotimes (i times)
@ -686,9 +733,6 @@ This value should always be overwritten.")
;; (unless (listp last-input-event) ;not a key event ;; (unless (listp last-input-event) ;not a key event
;; (exwm-input--fake-key last-input-event))) ;; (exwm-input--fake-key last-input-event)))
(defvar exwm-input--local-simulation-keys nil
"Whether simulation keys are local.")
(defun exwm-input--update-simulation-prefix-keys () (defun exwm-input--update-simulation-prefix-keys ()
"Update the list of prefix keys of simulation keys." "Update the list of prefix keys of simulation keys."
(setq exwm-input--simulation-prefix-keys nil) (setq exwm-input--simulation-prefix-keys nil)
@ -718,9 +762,13 @@ Its usage is the same with `exwm-input-set-simulation-keys'."
(exwm-input-set-simulation-keys simulation-keys))) (exwm-input-set-simulation-keys simulation-keys)))
;;;###autoload ;;;###autoload
(defun exwm-input-send-simulation-key (times) (cl-defun exwm-input-send-simulation-key (times)
"Fake a key event according to last input key sequence." "Fake a key event according to the last input key sequence.
Sending multiple fake keys at once is only supported by Emacs 27 and later."
(interactive "p") (interactive "p")
(unless (derived-mode-p 'exwm-mode)
(cl-return-from 'exwm-input-send-simulation-key))
(let ((pair (assoc (this-single-command-keys) exwm-input--simulation-keys))) (let ((pair (assoc (this-single-command-keys) exwm-input--simulation-keys)))
(when pair (when pair
(setq pair (cdr pair)) (setq pair (cdr pair))
@ -738,11 +786,6 @@ Its usage is the same with `exwm-input-set-simulation-keys'."
"Run in `post-command-hook'." "Run in `post-command-hook'."
(setq exwm-input--during-command nil)) (setq exwm-input--during-command nil))
(declare-function exwm-floating--stop-moveresize "exwm-floating.el"
(&rest _args))
(declare-function exwm-floating--do-moveresize "exwm-floating.el"
(data _synthetic))
(defun exwm-input--init () (defun exwm-input--init ()
"Initialize the keyboard module." "Initialize the keyboard module."
;; Refresh keyboard mapping ;; Refresh keyboard mapping

View file

@ -27,8 +27,35 @@
(require 'exwm-core) (require 'exwm-core)
(defvar exwm-floating-border-width) (defgroup exwm-layout nil
(defvar exwm-workspace--id-struts-alist) "Layout."
:version "25.3"
:group 'exwm)
(defcustom exwm-layout-show-all-buffers nil
"Non-nil to allow switching to buffers on other workspaces."
:type 'boolean)
(defvar exwm-layout--other-buffer-exclude-buffers nil
"List of buffers that should not be selected by `other-buffer'.")
(defvar exwm-layout--other-buffer-exclude-exwm-mode-buffers nil
"When non-nil, prevent EXWM buffers from being selected by `other-buffer'.")
(defvar exwm-layout--timer nil "Timer used to track echo area changes.")
(defvar exwm-workspace--current)
(declare-function exwm-input-grab-keyboard "exwm-input.el")
(declare-function exwm-input-release-keyboard "exwm-input.el")
(declare-function exwm-workspace--client-p "exwm-workspace.el"
(&optional frame))
(declare-function exwm-workspace--current-height "exwm-workspace.el")
(declare-function exwm-workspace--current-width "exwm-workspace.el")
(declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el")
(declare-function exwm-workspace--workspace-p "exwm-workspace.el"
(workspace))
(declare-function exwm-workspace-move-window "exwm-workspace.el"
(frame-or-index &optional id))
(defun exwm-layout--set-state (id state) (defun exwm-layout--set-state (id state)
"Set WM_STATE." "Set WM_STATE."
@ -99,23 +126,14 @@
(exwm-layout--set-state id xcb:icccm:WM_STATE:IconicState) (exwm-layout--set-state id xcb:icccm:WM_STATE:IconicState)
(xcb:flush exwm--connection)))) (xcb:flush exwm--connection))))
(defvar exwm-workspace--current)
(declare-function exwm-input-grab-keyboard "exwm-input.el")
(declare-function exwm-input-release-keyboard "exwm-input.el")
(declare-function exwm-workspace--current-height "exwm-workspace.el")
(declare-function exwm-workspace--current-width "exwm-workspace.el")
(declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el")
(declare-function exwm-workspace-move-window "exwm-workspace.el"
(frame-or-index &optional id))
;;;###autoload ;;;###autoload
(defun exwm-layout-set-fullscreen (&optional id) (cl-defun exwm-layout-set-fullscreen (&optional id)
"Make window ID fullscreen." "Make window ID fullscreen."
(interactive) (interactive)
(unless (and (or id (derived-mode-p 'exwm-mode))
(not (memq xcb:Atom:_NET_WM_STATE_FULLSCREEN exwm--ewmh-state)))
(cl-return-from 'exwm-layout-set-fullscreen))
(with-current-buffer (if id (exwm--id->buffer id) (window-buffer)) (with-current-buffer (if id (exwm--id->buffer id) (window-buffer))
(when (memq xcb:Atom:_NET_WM_STATE_FULLSCREEN exwm--ewmh-state)
(user-error "Already in full-screen mode"))
;; Expand the X window to fill the whole screen. ;; Expand the X window to fill the whole screen.
;; Rationale: Floating X windows may not be positioned at (0, 0) ;; Rationale: Floating X windows may not be positioned at (0, 0)
;; due to the extra border. ;; due to the extra border.
@ -139,12 +157,13 @@
(call-interactively #'exwm-input-release-keyboard))) (call-interactively #'exwm-input-release-keyboard)))
;;;###autoload ;;;###autoload
(defun exwm-layout-unset-fullscreen (&optional id) (cl-defun exwm-layout-unset-fullscreen (&optional id)
"Restore window from fullscreen state." "Restore window from fullscreen state."
(interactive) (interactive)
(unless (and (or id (derived-mode-p 'exwm-mode))
(memq xcb:Atom:_NET_WM_STATE_FULLSCREEN exwm--ewmh-state))
(cl-return-from 'exwm-layout-unset-fullscreen))
(with-current-buffer (if id (exwm--id->buffer id) (window-buffer)) (with-current-buffer (if id (exwm--id->buffer id) (window-buffer))
(unless (memq xcb:Atom:_NET_WM_STATE_FULLSCREEN exwm--ewmh-state)
(user-error "Not in full-screen mode"))
(if exwm--floating-frame (if exwm--floating-frame
(exwm-layout--show exwm--id (frame-root-window exwm--floating-frame)) (exwm-layout--show exwm--id (frame-root-window exwm--floating-frame))
(xcb:+request exwm--connection (xcb:+request exwm--connection
@ -165,21 +184,17 @@
(call-interactively #'exwm-input-grab-keyboard))) (call-interactively #'exwm-input-grab-keyboard)))
;;;###autoload ;;;###autoload
(defun exwm-layout-toggle-fullscreen (&optional id) (cl-defun exwm-layout-toggle-fullscreen (&optional id)
"Toggle fullscreen mode." "Toggle fullscreen mode."
(interactive (list (exwm--buffer->id (window-buffer)))) (interactive (list (exwm--buffer->id (window-buffer))))
(unless (or id (derived-mode-p 'exwm-mode))
(cl-return-from 'exwm-layout-toggle-fullscreen))
(when id (when id
(with-current-buffer (exwm--id->buffer id) (with-current-buffer (exwm--id->buffer id)
(if (memq xcb:Atom:_NET_WM_STATE_FULLSCREEN exwm--ewmh-state) (if (memq xcb:Atom:_NET_WM_STATE_FULLSCREEN exwm--ewmh-state)
(exwm-reset) (exwm-reset)
(exwm-layout-set-fullscreen id))))) (exwm-layout-set-fullscreen id)))))
(defvar exwm-layout--other-buffer-exclude-exwm-mode-buffers nil
"When non-nil, prevent EXWM buffers from being selected by `other-buffer'.")
(defvar exwm-layout--other-buffer-exclude-buffers nil
"List of buffers that should not be selected by `other-buffer'.")
(defun exwm-layout--other-buffer-predicate (buffer) (defun exwm-layout--other-buffer-predicate (buffer)
"Return non-nil when the BUFFER may be displayed in selected frame. "Return non-nil when the BUFFER may be displayed in selected frame.
@ -201,11 +216,6 @@ selected by `other-buffer'."
;; Do not select if already shown in some window. ;; Do not select if already shown in some window.
(not (get-buffer-window buffer t))))) (not (get-buffer-window buffer t)))))
(defvar exwm-layout-show-all-buffers nil
"Non-nil to allow switching to buffers on other workspaces.")
(declare-function exwm-workspace--workspace-p "exwm-workspace.el"
(workspace))
(defun exwm-layout--set-client-list-stacking () (defun exwm-layout--set-client-list-stacking ()
"Set _NET_CLIENT_LIST_STACKING." "Set _NET_CLIENT_LIST_STACKING."
(let (id clients-floating clients clients-iconic clients-other) (let (id clients-floating clients clients-iconic clients-other)
@ -301,9 +311,6 @@ selected by `other-buffer'."
(exwm-layout--set-client-list-stacking) (exwm-layout--set-client-list-stacking)
(xcb:flush exwm--connection)))) (xcb:flush exwm--connection))))
(declare-function exwm-workspace--client-p "exwm-workspace.el"
(&optional frame))
(defun exwm-layout--on-minibuffer-setup () (defun exwm-layout--on-minibuffer-setup ()
"Refresh layout when minibuffer grows." "Refresh layout when minibuffer grows."
(unless (exwm-workspace--client-p) (unless (exwm-workspace--client-p)
@ -479,8 +486,6 @@ See also `exwm-layout-enlarge-window'."
(exwm-layout-hide-mode-line) (exwm-layout-hide-mode-line)
(exwm-layout-show-mode-line)))) (exwm-layout-show-mode-line))))
(defvar exwm-layout--timer nil "Timer used to track echo area changes.")
(defun exwm-layout--init () (defun exwm-layout--init ()
"Initialize layout module." "Initialize layout module."
;; Auto refresh layout ;; Auto refresh layout

View file

@ -28,17 +28,66 @@
(require 'exwm-core) (require 'exwm-core)
(defvar exwm-manage-force-tiling nil (defgroup exwm-manage nil
"Non-nil to force managing all X windows in tiling layout. "Manage."
:version "25.3"
:group 'exwm)
You can still make the X windows floating afterwards.") (defcustom exwm-manage-finish-hook nil
(defvar exwm-manage-finish-hook nil
"Normal hook run after a window is just managed, in the context of the "Normal hook run after a window is just managed, in the context of the
corresponding buffer.") corresponding buffer."
:type 'hook)
(defcustom exwm-manage-force-tiling nil
"Non-nil to force managing all X windows in tiling layout.
You can still make the X windows floating afterwards."
:type 'boolean)
;; FIXME: Make the following values as small as possible.
(defconst exwm-manage--height-delta-min 5)
(defconst exwm-manage--width-delta-min 5)
;; The _MOTIF_WM_HINTS atom (see <Xm/MwmUtil.h> for more details)
;; It's currently only used in 'exwm-manage' module
(defvar exwm-manage--_MOTIF_WM_HINTS nil "_MOTIF_WM_HINTS atom.")
(defvar exwm-manage--desktop nil "The desktop X window.") (defvar exwm-manage--desktop nil "The desktop X window.")
(defvar exwm-manage--frame-outer-id-list nil
"List of window-outer-id's of all frames.")
(defvar exwm-manage--ping-lock nil
"Non-nil indicates EXWM is pinging a window.")
(defvar exwm-manage-ping-timeout 3 "Seconds to wait before killing a client.")
(defvar exwm-workspace--current)
(defvar exwm-workspace--id-struts-alist)
(defvar exwm-workspace--list)
(defvar exwm-workspace--switch-history-outdated)
(defvar exwm-workspace-current-index)
(declare-function exwm--update-class "exwm.el" (id &optional force))
(declare-function exwm--update-hints "exwm.el" (id &optional force))
(declare-function exwm--update-normal-hints "exwm.el" (id &optional force))
(declare-function exwm--update-protocols "exwm.el" (id &optional force))
(declare-function exwm--update-struts "exwm.el" (id))
(declare-function exwm--update-title "exwm.el" (id))
(declare-function exwm--update-transient-for "exwm.el" (id &optional force))
(declare-function exwm--update-window-type "exwm.el" (id &optional force))
(declare-function exwm-floating--set-floating "exwm-floating.el" (id))
(declare-function exwm-floating--unset-floating "exwm-floating.el" (id))
(declare-function exwm-input-grab-keyboard "exwm-input.el")
(declare-function exwm-layout--iconic-state-p "exwm-layout.el" (&optional id))
(declare-function exwm-workspace--count "exwm-workspace.el" ())
(declare-function exwm-workspace--current-height "exwm-workspace.el")
(declare-function exwm-workspace--current-width "exwm-workspace.el")
(declare-function exwm-workspace--set-desktop "exwm-workspace.el" (id))
(declare-function exwm-workspace--set-fullscreen "exwm-workspace.el" (frame))
(declare-function exwm-workspace--update-struts "exwm-workspace.el" ())
(declare-function exwm-workspace--update-workareas "exwm-workspace.el" ())
(declare-function exwm-workspace-move-window "exwm-workspace.el"
(frame-or-index &optional id))
(defun exwm-manage--update-geometry (id &optional force) (defun exwm-manage--update-geometry (id &optional force)
"Update window geometry." "Update window geometry."
(with-current-buffer (exwm--id->buffer id) (with-current-buffer (exwm--id->buffer id)
@ -58,10 +107,6 @@ corresponding buffer.")
(when reply (when reply
(setq exwm--ewmh-state (append (slot-value reply 'value) nil))))))) (setq exwm--ewmh-state (append (slot-value reply 'value) nil)))))))
;; The _MOTIF_WM_HINTS atom (see <Xm/MwmUtil.h> for more details)
;; It's currently only used in 'exwm-manage' module
(defvar exwm-manage--_MOTIF_WM_HINTS nil "_MOTIF_WM_HINTS atom.")
(defun exwm-manage--update-mwm-hints (id &optional force) (defun exwm-manage--update-mwm-hints (id &optional force)
"Update _MOTIF_WM_HINTS." "Update _MOTIF_WM_HINTS."
(with-current-buffer (exwm--id->buffer id) (with-current-buffer (exwm--id->buffer id)
@ -92,29 +137,6 @@ corresponding buffer.")
:window exwm--root :window exwm--root
:data (vconcat (mapcar #'car exwm--id-buffer-alist))))) :data (vconcat (mapcar #'car exwm--id-buffer-alist)))))
(defvar exwm-workspace--current)
(defvar exwm-workspace--switch-history-outdated)
(defvar exwm-workspace-current-index)
(defvar exwm-workspace--workareas)
(declare-function exwm--update-window-type "exwm.el" (id &optional force))
(declare-function exwm--update-class "exwm.el" (id &optional force))
(declare-function exwm--update-transient-for "exwm.el" (id &optional force))
(declare-function exwm--update-normal-hints "exwm.el" (id &optional force))
(declare-function exwm--update-title "exwm.el" (id))
(declare-function exwm--update-hints "exwm.el" (id &optional force))
(declare-function exwm--update-protocols "exwm.el" (id &optional force))
(declare-function exwm--update-struts "exwm.el" (id))
(declare-function exwm-floating--set-floating "exwm-floating.el" (id))
(declare-function exwm-floating--unset-floating "exwm-floating.el" (id))
(declare-function exwm-input-grab-keyboard "exwm-input.el")
(declare-function exwm-workspace--current-height "exwm-workspace.el")
(declare-function exwm-workspace--current-width "exwm-workspace.el")
(declare-function exwm-workspace--set-desktop "exwm-workspace.el" (id))
(declare-function exwm-workspace--count "exwm-workspace.el" ())
(declare-function exwm-workspace-move-window "exwm-workspace.el"
(frame-or-index &optional id))
(defun exwm-manage--manage-window (id) (defun exwm-manage--manage-window (id)
"Manage window ID." "Manage window ID."
(exwm--log "Try to manage #x%x" id) (exwm--log "Try to manage #x%x" id)
@ -251,13 +273,6 @@ corresponding buffer.")
(exwm-layout-set-fullscreen id)) (exwm-layout-set-fullscreen id))
(run-hooks 'exwm-manage-finish-hook))))) (run-hooks 'exwm-manage-finish-hook)))))
(defvar exwm-workspace--id-struts-alist)
(defvar exwm-workspace--list)
(declare-function exwm-workspace--update-struts "exwm-workspace.el" ())
(declare-function exwm-workspace--update-workareas "exwm-workspace.el" ())
(declare-function exwm-workspace--set-fullscreen "exwm-workspace.el" (frame))
(defun exwm-manage--unmanage-window (id &optional withdraw-only) (defun exwm-manage--unmanage-window (id &optional withdraw-only)
"Unmanage window ID. "Unmanage window ID.
@ -350,10 +365,6 @@ manager is shutting down."
(xcb:flush exwm--connection) (xcb:flush exwm--connection)
(exwm-manage--manage-window i))))))) (exwm-manage--manage-window i)))))))
(defvar exwm-manage--ping-lock nil
"Non-nil indicates EXWM is pinging a window.")
(defvar exwm-manage-ping-timeout 3 "Seconds to wait before killing a client.")
(defun exwm-manage--kill-buffer-query-function () (defun exwm-manage--kill-buffer-query-function ()
"Run in `kill-buffer-query-functions'." "Run in `kill-buffer-query-functions'."
(catch 'return (catch 'return
@ -447,13 +458,6 @@ Would you like to kill it? "
(xcb:+request exwm--connection ,request)))) (xcb:+request exwm--connection ,request))))
(xcb:flush exwm--connection))) (xcb:flush exwm--connection)))
;; FIXME: Make the following values as small as possible.
(defconst exwm-manage--width-delta-min 5)
(defconst exwm-manage--height-delta-min 5)
(defvar exwm-manage--frame-outer-id-list nil
"List of window-outer-id's of all frames.")
(defun exwm-manage--add-frame (frame) (defun exwm-manage--add-frame (frame)
"Run in `after-make-frame-functions'." "Run in `after-make-frame-functions'."
(when (display-graphic-p frame) (when (display-graphic-p frame)
@ -560,8 +564,6 @@ border-width: %d; sibling: #x%x; stack-mode: %d"
:stack-mode stack-mode))))))) :stack-mode stack-mode)))))))
(xcb:flush exwm--connection)) (xcb:flush exwm--connection))
(declare-function exwm-layout--iconic-state-p "exwm-layout.el" (&optional id))
(defun exwm-manage--on-MapRequest (data _synthetic) (defun exwm-manage--on-MapRequest (data _synthetic)
"Handle MapRequest event." "Handle MapRequest event."
(let ((obj (make-instance 'xcb:MapRequest))) (let ((obj (make-instance 'xcb:MapRequest)))

View file

@ -50,19 +50,42 @@
(require 'xcb-randr) (require 'xcb-randr)
(require 'exwm-core) (require 'exwm-core)
(defvar exwm-randr-workspace-output-plist nil) (defgroup exwm-randr nil
"RandR."
:version "25.3"
:group 'exwm)
(defvar exwm-randr-refresh-hook nil (defcustom exwm-randr-refresh-hook nil
"Normal hook run when the RandR module just refreshed.") "Normal hook run when the RandR module just refreshed."
:type 'hook)
(defcustom exwm-randr-screen-change-hook nil
"Normal hook run when screen changes."
:type 'hook)
(defcustom exwm-randr-workspace-output-plist nil
"Plist mapping workspace to output.
If an output is not available, the workspaces mapped to it are displayed on
the primary output until it becomes available. Unspecified workspaces are
all mapped to the primary output. For example, with the following value
workspace other than 1 and 3 would always be displayed on the primary output
where workspace 1 and 3 would be displayed on their corresponding output
whenever the outputs are available.
'(1 \"HDMI-1\" 3 \"DP-1\")
The outputs available can be identified by running the 'xrandr' utility with
the first one in result being the primary output."
:type '(plist :key-type integer :value-type string))
(defvar exwm-workspace--fullscreen-frame-count) (defvar exwm-workspace--fullscreen-frame-count)
(defvar exwm-workspace--list) (defvar exwm-workspace--list)
(declare-function exwm-workspace--count "exwm-workspace.el") (declare-function exwm-workspace--count "exwm-workspace.el")
(declare-function exwm-workspace--set-fullscreen "exwm-workspace.el" (frame))
(declare-function exwm-workspace--update-workareas "exwm-workspace.el" ())
(declare-function exwm-workspace--show-minibuffer "exwm-workspace.el" ())
(declare-function exwm-workspace--set-desktop-geometry "exwm-workspace.el" ()) (declare-function exwm-workspace--set-desktop-geometry "exwm-workspace.el" ())
(declare-function exwm-workspace--set-fullscreen "exwm-workspace.el" (frame))
(declare-function exwm-workspace--show-minibuffer "exwm-workspace.el" ())
(declare-function exwm-workspace--update-workareas "exwm-workspace.el" ())
(defun exwm-randr--refresh () (defun exwm-randr--refresh ()
"Refresh workspaces according to the updated RandR info." "Refresh workspaces according to the updated RandR info."
@ -122,9 +145,6 @@
(xcb:flush exwm--connection) (xcb:flush exwm--connection)
(run-hooks 'exwm-randr-refresh-hook)))) (run-hooks 'exwm-randr-refresh-hook))))
(defvar exwm-randr-screen-change-hook nil
"Normal hook run when screen changes.")
(defun exwm-randr--init () (defun exwm-randr--init ()
"Initialize RandR extension and EXWM RandR module." "Initialize RandR extension and EXWM RandR module."
(if (= 0 (slot-value (xcb:get-extension-data exwm--connection 'xcb:randr) (if (= 0 (slot-value (xcb:get-extension-data exwm--connection 'xcb:randr)

View file

@ -50,22 +50,38 @@
(owner :initarg :owner :type xcb:WINDOW)) ;new slot (owner :initarg :owner :type xcb:WINDOW)) ;new slot
:documentation "A systemtray client message.") :documentation "A systemtray client message.")
(defgroup exwm-systemtray nil
"System tray."
:version "25.3"
:group 'exwm)
(defcustom exwm-systemtray-height nil
"System tray height.
You shall use the default value if using auto-hide minibuffer."
:type 'integer)
(defcustom exwm-systemtray-icon-gap 2
"Gap between icons."
:type 'integer)
;; GTK icons require at least 16 pixels to show normally. ;; GTK icons require at least 16 pixels to show normally.
(defconst exwm-systemtray--icon-min-size 16 "Minimum icon size.") (defconst exwm-systemtray--icon-min-size 16 "Minimum icon size.")
(defvar exwm-systemtray-height nil "System tray height.
You shall use the default value if using auto-hide minibuffer.")
(defvar exwm-systemtray-icon-gap 2 "Gap between icons.")
(defvar exwm-systemtray--connection nil "The X connection.") (defvar exwm-systemtray--connection nil "The X connection.")
(defvar exwm-systemtray--list nil "The icon list.")
(defvar exwm-systemtray--selection-owner-window nil
"The selection owner window.")
(defvar exwm-systemtray--embedder nil "The embedder window.") (defvar exwm-systemtray--embedder nil "The embedder window.")
(defvar exwm-systemtray--list nil "The icon list.")
(defvar exwm-systemtray--selection-owner-window nil
"The selection owner window.")
(defvar exwm-workspace--current) (defvar exwm-workspace--current)
(defvar exwm-workspace--minibuffer)
(defvar exwm-workspace--workareas)
(defvar exwm-workspace-current-index)
(defvar xcb:Atom:_NET_SYSTEM_TRAY_S0)
(declare-function exwm-workspace--current-height "exwm-workspace.el") (declare-function exwm-workspace--current-height "exwm-workspace.el")
(declare-function exwm-workspace--current-width "exwm-workspace.el") (declare-function exwm-workspace--current-width "exwm-workspace.el")
(declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el") (declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el")
@ -304,9 +320,6 @@ You shall use the default value if using auto-hide minibuffer.")
:event (xcb:marshal obj exwm-systemtray--connection)))) :event (xcb:marshal obj exwm-systemtray--connection))))
(xcb:flush exwm-systemtray--connection)) (xcb:flush exwm-systemtray--connection))
(defvar exwm-workspace--workareas)
(defvar exwm-workspace-current-index)
(defun exwm-systemtray--on-workspace-switch () (defun exwm-systemtray--on-workspace-switch ()
"Reparent/Refresh the system tray in `exwm-workspace-switch-hook'." "Reparent/Refresh the system tray in `exwm-workspace-switch-hook'."
(unless (exwm-workspace--minibuffer-own-frame-p) (unless (exwm-workspace--minibuffer-own-frame-p)
@ -339,9 +352,6 @@ You shall use the default value if using auto-hide minibuffer.")
(defalias 'exwm-systemtray--on-struts-update (defalias 'exwm-systemtray--on-struts-update
#'exwm-systemtray--on-randr-refresh) #'exwm-systemtray--on-randr-refresh)
(defvar xcb:Atom:_NET_SYSTEM_TRAY_S0)
(defvar exwm-workspace--minibuffer)
(cl-defun exwm-systemtray--init () (cl-defun exwm-systemtray--init ()
"Initialize system tray module." "Initialize system tray module."
(cl-assert (not exwm-systemtray--connection)) (cl-assert (not exwm-systemtray--connection))

View file

@ -29,16 +29,110 @@
(require 'exwm-core) (require 'exwm-core)
(defvar exwm-manage--desktop) (defgroup exwm-workspace nil
"Workspace."
:version "25.3"
:group 'exwm)
(defvar exwm-workspace-number 1 "Initial number of workspaces.") (defcustom exwm-workspace-switch-hook nil
(defvar exwm-workspace--list nil "List of all workspaces (Emacs frames).") "Normal hook run after switching workspace."
(defvar exwm-workspace--current nil "Current active workspace.") :type 'hook)
(defvar exwm-workspace-current-index 0 "Index of current active workspace.")
(defvar exwm-workspace-index-map #'number-to-string (defcustom exwm-workspace-list-change-hook nil
"Normal hook run when the workspace list is changed (workspace added,
deleted, moved, etc)."
:type 'hook)
(defcustom exwm-workspace-show-all-buffers nil
"Non-nil to show buffers on other workspaces."
:type 'boolean)
(defcustom exwm-workspace-number 1
"Initial number of workspaces."
:type 'integer)
(defcustom exwm-workspace-index-map #'number-to-string
"Function for mapping a workspace index to a string for display. "Function for mapping a workspace index to a string for display.
By default `number-to-string' is applied which yields 0 1 2 ... .") By default `number-to-string' is applied which yields 0 1 2 ... ."
:type 'function)
(defcustom exwm-workspace-minibuffer-position nil
"Position of the minibuffer frame."
:type '(choice (const :tag "Bottom (fixed)" nil)
(const :tag "Bottom (auto-hide)" bottom)
(const :tag "Top (auto-hide)" top)))
(defcustom exwm-workspace-display-echo-area-timeout 1
"Timeout for displaying echo area."
:type 'integer)
(defcustom exwm-workspace-switch-create-limit 10
"Number of workspaces `exwm-workspace-switch-create' allowed to create
each time."
:type 'integer)
(defvar exwm-workspace-current-index 0 "Index of current active workspace.")
(defvar exwm-workspace--attached-minibuffer-height 0
"Height (in pixel) of the attached minibuffer.
If the minibuffer is detached, this value is 0.")
(defvar exwm-workspace--client nil
"The 'client' frame parameter of emacsclient frames.")
(defvar exwm-workspace--create-silently nil
"When non-nil workspaces are created in the background (not switched to).
Please manually run the hook `exwm-workspace-list-change-hook' afterwards.")
(defvar exwm-workspace--current nil "Current active workspace.")
(defvar exwm-workspace--display-echo-area-timer nil
"Timer for auto-hiding echo area.")
(defvar exwm-workspace--id-struts-alist nil "Alist of X window and struts.")
(defvar exwm-workspace--fullscreen-frame-count 0
"Count the fullscreen workspace frames.")
(defvar exwm-workspace--list nil "List of all workspaces (Emacs frames).")
(defvar exwm-workspace--minibuffer nil
"The minibuffer frame shared among all frames.")
(defvar exwm-workspace--prompt-add-allowed nil
"Non-nil to allow adding workspace from the prompt.")
(defvar exwm-workspace--prompt-delete-allowed nil
"Non-nil to allow deleting workspace from the prompt.")
(defvar exwm-workspace--struts nil "Areas occupied by struts.")
(defvar exwm-workspace--switch-history nil
"History for `read-from-minibuffer' to interactively switch workspace.")
(defvar exwm-workspace--switch-history-outdated nil
"Non-nil to indicate `exwm-workspace--switch-history' is outdated.")
(defvar exwm-workspace--timer nil "Timer used to track echo area changes.")
(defvar exwm-workspace--update-workareas-hook nil
"Normal hook run when workareas get updated.")
(defvar exwm-workspace--workareas nil "Workareas (struts excluded).")
(defvar exwm-input--during-command)
(defvar exwm-layout-show-all-buffers)
(defvar exwm-manage--desktop)
(declare-function exwm--exit "exwm.el")
(declare-function exwm-input--on-buffer-list-update "exwm-input.el" ())
(declare-function exwm-layout--hide "exwm-layout.el" (id))
(declare-function exwm-layout--other-buffer-predicate "exwm-layout.el"
(buffer))
(declare-function exwm-layout--refresh "exwm-layout.el")
(declare-function exwm-layout--show "exwm-layout.el" (id &optional window))
(defsubst exwm-workspace--position (frame) (defsubst exwm-workspace--position (frame)
"Retrieve index of given FRAME in workspace list. "Retrieve index of given FRAME in workspace list.
@ -58,20 +152,6 @@ NIL if FRAME is not a workspace"
"Return non-nil if FRAME is an emacsclient frame." "Return non-nil if FRAME is an emacsclient frame."
(frame-parameter frame 'client)) (frame-parameter frame 'client))
(defun exwm-workspace--workspace-from-frame-or-index (frame-or-index)
"Retrieve the workspace frame from FRAME-OR-INDEX."
(cond
((framep frame-or-index)
(unless (exwm-workspace--position frame-or-index)
(user-error "[EXWM] Frame is not a workspace %S" frame-or-index))
frame-or-index)
((integerp frame-or-index)
(unless (and (<= 0 frame-or-index)
(< frame-or-index (exwm-workspace--count)))
(user-error "[EXWM] Workspace index out of range: %d" frame-or-index))
(elt exwm-workspace--list frame-or-index))
(t (user-error "[EXWM] Invalid workspace: %s" frame-or-index))))
(defvar exwm-workspace--switch-map (defvar exwm-workspace--switch-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(define-key map [t] (lambda () (interactive))) (define-key map [t] (lambda () (interactive)))
@ -98,10 +178,19 @@ NIL if FRAME is not a workspace"
map) map)
"Keymap used for interactively switch workspace.") "Keymap used for interactively switch workspace.")
(defvar exwm-workspace--switch-history nil (defun exwm-workspace--workspace-from-frame-or-index (frame-or-index)
"History for `read-from-minibuffer' to interactively switch workspace.") "Retrieve the workspace frame from FRAME-OR-INDEX."
(defvar exwm-workspace--switch-history-outdated nil (cond
"Non-nil to indicate `exwm-workspace--switch-history' is outdated.") ((framep frame-or-index)
(unless (exwm-workspace--position frame-or-index)
(user-error "[EXWM] Frame is not a workspace %S" frame-or-index))
frame-or-index)
((integerp frame-or-index)
(unless (and (<= 0 frame-or-index)
(< frame-or-index (exwm-workspace--count)))
(user-error "[EXWM] Workspace index out of range: %d" frame-or-index))
(elt exwm-workspace--list frame-or-index))
(t (user-error "[EXWM] Invalid workspace: %s" frame-or-index))))
(defun exwm-workspace--prompt-for-workspace (&optional prompt) (defun exwm-workspace--prompt-for-workspace (&optional prompt)
"Prompt for a workspace, returning the workspace frame." "Prompt for a workspace, returning the workspace frame."
@ -117,15 +206,6 @@ NIL if FRAME is not a workspace"
:test #'equal))) :test #'equal)))
(elt exwm-workspace--list workspace-idx))) (elt exwm-workspace--list workspace-idx)))
(defvar exwm-workspace--prompt-add-allowed nil
"Non-nil to allow adding workspace from the prompt.")
(defvar exwm-workspace--prompt-delete-allowed nil
"Non-nil to allow deleting workspace from the prompt.")
(defvar exwm-workspace--create-silently nil
"When non-nil workspaces are created in the background (not switched to).
Please manually run the hook `exwm-workspace-list-change-hook' afterwards.")
(defun exwm-workspace--prompt-add () (defun exwm-workspace--prompt-add ()
"Add workspace from the prompt." "Add workspace from the prompt."
(interactive) (interactive)
@ -182,20 +262,6 @@ Please manually run the hook `exwm-workspace-list-change-hook' afterwards.")
sequence "")) sequence ""))
sequence))))) sequence)))))
(defvar exwm-workspace-show-all-buffers nil
"Non-nil to show buffers on other workspaces.")
(defvar exwm-workspace--minibuffer nil
"The minibuffer frame shared among all frames.")
(defvar exwm-workspace-minibuffer-position nil
"Position of the minibuffer frame.
Value nil means to use the default position which is fixed at bottom, while
'top and 'bottom mean to use an auto-hiding minibuffer.")
(defvar exwm-workspace-display-echo-area-timeout 1
"Timeout for displaying echo area.")
(defvar exwm-workspace--display-echo-area-timer nil
"Timer for auto-hiding echo area.")
;;;###autoload ;;;###autoload
(defun exwm-workspace--get-geometry (frame) (defun exwm-workspace--get-geometry (frame)
"Return the geometry of frame FRAME." "Return the geometry of frame FRAME."
@ -227,9 +293,6 @@ Value nil means to use the default position which is fixed at bottom, while
"Reports whether the minibuffer is displayed in its own frame." "Reports whether the minibuffer is displayed in its own frame."
(memq exwm-workspace-minibuffer-position '(top bottom))) (memq exwm-workspace-minibuffer-position '(top bottom)))
(defvar exwm-workspace--id-struts-alist nil "Alist of X window and struts.")
(defvar exwm-workspace--struts nil "Areas occupied by struts.")
(defun exwm-workspace--update-struts () (defun exwm-workspace--update-struts ()
"Update `exwm-workspace--struts'." "Update `exwm-workspace--struts'."
(setq exwm-workspace--struts nil) (setq exwm-workspace--struts nil)
@ -250,10 +313,6 @@ Value nil means to use the default position which is fixed at bottom, while
(setq exwm-workspace--struts (setq exwm-workspace--struts
(append exwm-workspace--struts (list struts*)))))))))) (append exwm-workspace--struts (list struts*))))))))))
(defvar exwm-workspace--workareas nil "Workareas (struts excluded).")
(defvar exwm-workspace--update-workareas-hook nil
"Normal hook run when workareas get updated.")
(defun exwm-workspace--update-workareas () (defun exwm-workspace--update-workareas ()
"Update `exwm-workspace--workareas'." "Update `exwm-workspace--workareas'."
(let ((root-width (x-display-pixel-width)) (let ((root-width (x-display-pixel-width))
@ -318,9 +377,6 @@ Value nil means to use the default position which is fixed at bottom, while
(xcb:flush exwm--connection)) (xcb:flush exwm--connection))
(run-hooks 'exwm-workspace--update-workareas-hook)) (run-hooks 'exwm-workspace--update-workareas-hook))
(defvar exwm-workspace--fullscreen-frame-count 0
"Count the fullscreen workspace frames.")
(defun exwm-workspace--set-fullscreen (frame) (defun exwm-workspace--set-fullscreen (frame)
"Make frame FRAME fullscreen according to `exwm-workspace--workareas'." "Make frame FRAME fullscreen according to `exwm-workspace--workareas'."
(let ((workarea (elt exwm-workspace--workareas (let ((workarea (elt exwm-workspace--workareas
@ -342,11 +398,6 @@ Value nil means to use the default position which is fixed at bottom, while
(when exwm-workspace--fullscreen-frame-count (when exwm-workspace--fullscreen-frame-count
(cl-incf exwm-workspace--fullscreen-frame-count))) (cl-incf exwm-workspace--fullscreen-frame-count)))
(defvar exwm-workspace--attached-minibuffer-height 0
"Height (in pixel) of the attached minibuffer.
If the minibuffer is detached, this value is 0.")
(defun exwm-workspace--resize-minibuffer-frame () (defun exwm-workspace--resize-minibuffer-frame ()
"Resize minibuffer (and its container) to fit the size of workspace." "Resize minibuffer (and its container) to fit the size of workspace."
(cl-assert (exwm-workspace--minibuffer-own-frame-p)) (cl-assert (exwm-workspace--minibuffer-own-frame-p))
@ -434,14 +485,13 @@ PREFIX-DIGITS is a list of the digits introduced so far."
(goto-history-element (1+ n)) (goto-history-element (1+ n))
(exit-minibuffer)) (exit-minibuffer))
(defvar exwm-workspace-switch-hook nil
"Normal hook run after switching workspace.")
;;;###autoload ;;;###autoload
(defun exwm-workspace-switch (frame-or-index &optional force) (defun exwm-workspace-switch (frame-or-index &optional force)
"Switch to workspace INDEX. Query for FRAME-OR-INDEX if it's not specified. "Switch to workspace INDEX (0-based).
The optional FORCE option is for internal use only." Query for the index if not specified when called interactively. Passing a
workspace frame as the first option or making use of the rest options are
for internal use only."
(interactive (interactive
(list (list
(unless (and (eq major-mode 'exwm-mode) (unless (and (eq major-mode 'exwm-mode)
@ -518,13 +568,11 @@ The optional FORCE option is for internal use only."
(run-hooks 'focus-in-hook) (run-hooks 'focus-in-hook)
(run-hooks 'exwm-workspace-switch-hook))) (run-hooks 'exwm-workspace-switch-hook)))
(defvar exwm-workspace-switch-create-limit 10
"Number of workspaces `exwm-workspace-switch-create' allowed to create
each time.")
;;;###autoload ;;;###autoload
(defun exwm-workspace-switch-create (frame-or-index) (defun exwm-workspace-switch-create (frame-or-index)
"Switch to workspace FRAME-OR-INDEX, creating it if it does not exist yet." "Switch to workspace INDEX or creating it first if it does not exist yet.
Passing a workspace frame as the first option is for internal use only."
(interactive) (interactive)
(if (or (framep frame-or-index) (if (or (framep frame-or-index)
(< frame-or-index (exwm-workspace--count))) (< frame-or-index (exwm-workspace--count)))
@ -537,10 +585,6 @@ each time.")
(run-hooks 'exwm-workspace-list-change-hook)) (run-hooks 'exwm-workspace-list-change-hook))
(exwm-workspace-switch frame-or-index))) (exwm-workspace-switch frame-or-index)))
(defvar exwm-workspace-list-change-hook nil
"Normal hook run when the workspace list is changed (workspace added,
deleted, moved, etc).")
;;;###autoload ;;;###autoload
(defun exwm-workspace-swap (workspace1 workspace2) (defun exwm-workspace-swap (workspace1 workspace2)
"Interchange position of WORKSPACE1 with that of WORKSPACE2." "Interchange position of WORKSPACE1 with that of WORKSPACE2."
@ -579,6 +623,7 @@ deleted, moved, etc).")
;;;###autoload ;;;###autoload
(defun exwm-workspace-move (workspace nth) (defun exwm-workspace-move (workspace nth)
"Move WORKSPACE to the NTH position. "Move WORKSPACE to the NTH position.
When called interactively, prompt for a workspace and move current one just When called interactively, prompt for a workspace and move current one just
before it." before it."
(interactive (interactive
@ -645,13 +690,6 @@ INDEX must not exceed the current number of workspaces."
:window id :window id
:data (exwm-workspace--position exwm--frame))))) :data (exwm-workspace--position exwm--frame)))))
(declare-function exwm-input--on-buffer-list-update "exwm-input.el" ())
(declare-function exwm-layout--show "exwm-layout.el" (id &optional window))
(declare-function exwm-layout--hide "exwm-layout.el" (id))
(declare-function exwm-layout--refresh "exwm-layout.el")
(declare-function exwm-layout--other-buffer-predicate "exwm-layout.el"
(buffer))
;;;###autoload ;;;###autoload
(defun exwm-workspace-move-window (frame-or-index &optional id) (defun exwm-workspace-move-window (frame-or-index &optional id)
"Move window ID to workspace FRAME-OR-INDEX." "Move window ID to workspace FRAME-OR-INDEX."
@ -780,8 +818,6 @@ INDEX must not exceed the current number of workspaces."
(xcb:flush exwm--connection))) (xcb:flush exwm--connection)))
(setq exwm-workspace--switch-history-outdated t))) (setq exwm-workspace--switch-history-outdated t)))
(defvar exwm-layout-show-all-buffers)
;;;###autoload ;;;###autoload
(defun exwm-workspace-switch-to-buffer (buffer-or-name) (defun exwm-workspace-switch-to-buffer (buffer-or-name)
"Make the current Emacs window display another buffer." "Make the current Emacs window display another buffer."
@ -1049,8 +1085,6 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first."
(remove-hook 'post-command-hook #'exwm-workspace--update-minibuffer-height) (remove-hook 'post-command-hook #'exwm-workspace--update-minibuffer-height)
(exwm-workspace--hide-minibuffer))) (exwm-workspace--hide-minibuffer)))
(defvar exwm-input--during-command)
(defun exwm-workspace--on-echo-area-dirty () (defun exwm-workspace--on-echo-area-dirty ()
"Run when new message arrives to show the echo area and its container." "Run when new message arrives to show the echo area and its container."
(when (and (not (active-minibuffer-window)) (when (and (not (active-minibuffer-window))
@ -1075,12 +1109,6 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first."
(cancel-timer exwm-workspace--display-echo-area-timer) (cancel-timer exwm-workspace--display-echo-area-timer)
(setq exwm-workspace--display-echo-area-timer nil)))) (setq exwm-workspace--display-echo-area-timer nil))))
(defvar exwm-workspace--client nil
"The 'client' frame parameter of emacsclient frames.")
(declare-function exwm-manage--unmanage-window "exwm-manage.el")
(declare-function exwm--exit "exwm.el")
(defun exwm-workspace--confirm-kill-emacs (prompt &optional force) (defun exwm-workspace--confirm-kill-emacs (prompt &optional force)
"Confirm before exiting Emacs." "Confirm before exiting Emacs."
(when (cond (when (cond
@ -1157,8 +1185,6 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first."
:width (x-display-pixel-width) :width (x-display-pixel-width)
:height (x-display-pixel-height)))) :height (x-display-pixel-height))))
(defvar exwm-workspace--timer nil "Timer used to track echo area changes.")
(defun exwm-workspace--add-frame-as-workspace (frame) (defun exwm-workspace--add-frame-as-workspace (frame)
"Configure frame FRAME to be treated as a workspace." "Configure frame FRAME to be treated as a workspace."
(cond (cond

59
exwm.el
View file

@ -72,9 +72,41 @@
(require 'exwm-manage) (require 'exwm-manage)
(require 'exwm-input) (require 'exwm-input)
(defgroup exwm nil
"Emacs X Window Manager."
:tag "EXWM"
:version "25.3"
:group 'applications
:prefix "exwm-")
(defcustom exwm-init-hook nil
"Normal hook run when EXWM has just finished initialization."
:type 'hook)
(defcustom exwm-exit-hook nil
"Normal hook run just before EXWM exits."
:type 'hook)
(defcustom exwm-update-class-hook nil
"Normal hook run when window class is updated."
:type 'hook)
(defcustom exwm-update-title-hook nil
"Normal hook run when window title is updated."
:type 'hook)
(defcustom exwm-blocking-subrs '(x-file-dialog x-popup-dialog x-select-font)
"Subrs (primitives) that would normally block EXWM."
:type '(repeat function))
(defconst exwm--server-name "server-exwm"
"Name of the subordinate Emacs server.")
(defvar exwm--server-process nil "Process of the subordinate Emacs server.")
;;;###autoload ;;;###autoload
(defun exwm-reset () (defun exwm-reset ()
"Reset window to standard state: non-fullscreen, line-mode." "Reset the state of the selected window (non-fullscreen, line-mode, etc)."
(interactive) (interactive)
(with-current-buffer (window-buffer) (with-current-buffer (window-buffer)
(when (eq major-mode 'exwm-mode) (when (eq major-mode 'exwm-mode)
@ -123,9 +155,6 @@
(when reply ;nil when destroyed (when reply ;nil when destroyed
(setq exwm-window-type (append (slot-value reply 'value) nil))))))) (setq exwm-window-type (append (slot-value reply 'value) nil)))))))
(defvar exwm-update-class-hook nil
"Normal hook run when window class is updated.")
(defun exwm--update-class (id &optional force) (defun exwm--update-class (id &optional force)
"Update WM_CLASS." "Update WM_CLASS."
(with-current-buffer (exwm--id->buffer id) (with-current-buffer (exwm--id->buffer id)
@ -138,9 +167,6 @@
(when (and exwm-instance-name exwm-class-name) (when (and exwm-instance-name exwm-class-name)
(run-hooks 'exwm-update-class-hook))))))) (run-hooks 'exwm-update-class-hook)))))))
(defvar exwm-update-title-hook nil
"Normal hook run when window title is updated.")
(defun exwm--update-utf8-title (id &optional force) (defun exwm--update-utf8-title (id &optional force)
"Update _NET_WM_NAME." "Update _NET_WM_NAME."
(with-current-buffer (exwm--id->buffer id) (with-current-buffer (exwm--id->buffer id)
@ -645,9 +671,6 @@
:property p)) :property p))
(xcb:flush exwm--connection))) (xcb:flush exwm--connection)))
(defvar exwm-init-hook nil
"Normal hook run when EXWM has just finished initialization.")
(defun exwm-init (&optional frame) (defun exwm-init (&optional frame)
"Initialize EXWM." "Initialize EXWM."
(if frame (if frame
@ -692,8 +715,6 @@
(exwm-manage--scan) (exwm-manage--scan)
(run-hooks 'exwm-init-hook))))) (run-hooks 'exwm-init-hook)))))
(defvar exwm-exit-hook nil "Normal hook run just before EXWM exits.")
(defun exwm--exit () (defun exwm--exit ()
"Exit EXWM." "Exit EXWM."
(run-hooks 'exwm-exit-hook) (run-hooks 'exwm-exit-hook)
@ -705,9 +726,6 @@
(exwm-layout--exit) (exwm-layout--exit)
(exwm--exit-icccm-ewmh)) (exwm--exit-icccm-ewmh))
(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) (defun exwm-enable (&optional undo)
"Enable/Disable EXWM." "Enable/Disable EXWM."
(pcase undo (pcase undo
@ -734,10 +752,6 @@
(dolist (i exwm-blocking-subrs) (dolist (i exwm-blocking-subrs)
(advice-add i :around #'exwm--server-eval-at))))) (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 () (defun exwm--server-stop ()
"Stop the subordinate Emacs server." "Stop the subordinate Emacs server."
(server-force-delete exwm--server-name) (server-force-delete exwm--server-name)
@ -784,13 +798,6 @@
;; For other types, return the value as-is. ;; For other types, return the value as-is.
(t result)))))) (t result))))))
(define-obsolete-function-alias 'exwm-enable-ido-workaround 'exwm-config-ido
"25.1" "Enable workarounds for Ido.")
(defun exwm-disable-ido-workaround ()
"This function does nothing actually."
(declare (obsolete nil "25.1")))
(provide 'exwm) (provide 'exwm)

View file

@ -1,6 +1,9 @@
# Disable access control # Disable access control
xhost +SI:localuser:$USER xhost +SI:localuser:$USER
# Make Java applications aware this is a non-reparenting window manager.
export _JAVA_AWT_WM_NONREPARENTING=1
# Themes, etc # Themes, etc
gnome-settings-daemon & gnome-settings-daemon &