EXWM
EXWM
Note: Tiling window managers like EXWM are usually configured as standalone applications without desktop environments /
session managers. However it's possible to substitute the window managers of certain desktop environments (e.g. LXDE) with
EXWM, or even with recent Gnome (e.g. exwm-gnome-flashback). Most contents in this document still apply there, but have a
look at the section on logging out with LXDE.
Note: As of 0.17 EXWM provides a Customize interface and most configuration options discussed here are also available
there.
Prerequisites
There's no specific prerequisite indeed. But if there have to be some, here they are (should be easily satisfied):
GNU Emacs with a version higher than 24.4, preferably 25 or higher versions. Also 64-bit build or 32-bit build with --
with-wide-int set is preferred. You should probably hide menu-bar, tool-bar, scroll-bar etc to make more room for X
windows.
X11 server (a recent version please).
(optional) dbus-launch .
(optional) gnome-settings-daemon (or other setting daemons).
Installation
Note: Emacs 24 users should install the cl-generic package from GNU ELPA as well.
Bootstrap
For those impatient: you might start trying EXWM with the following minimal steps. You should revisit this document later to
tweak EXWM if you decide to use it. Also, there is an example configuration that you might find it useful as a starting point.
(require 'exwm)
(require 'exwm-config)
(exwm-config-default)
xinit -- vt01
Note: Do not use (exwm-config-default) in your .emacs when you have a customized configuration.
P.S. New users often wonder how to properly launch an application in EXWM. The answer is it doesn't matter because EXWM
is a serious X window manager and knows how to do it correctly. Do not launch applications with M-! ( shell-command )
though as it will block Emacs and therefore freeze EXWM. The default/example configuration provides s-& to do this
conveniently.
Conventions
This section discusses some conventions which you should make clear before going through the rest of this document.
Note: EXWM must be enabled with (exwm-enable) (this is already taken care of in (exwm-config-default) ) before the
first Emacs frame is spawned. Thus you should add (exwm-enable) to your .emacs . It's always safe to call exwm-enable :
EXWM will just complain it's unable to start if there is another window manager. It is also possible to start EXWM from the
Emacs daemon: emacs --daemon -f exwm-enable .
An X window in this document exclusively refers to a top-level X window created by an application. An application may create
multiple such X windows; EXWM just manages them respectively. That is, what EXWM sees are merely top-level X windows; it
does not care about which application creates them.
exwm-mode is a major mode provided by EXWM to manage X windows. A buffer created in exwm-mode records all information
about the corresponding X window. exwm-mode also provides useful features to interact with that X window. Things dedicated
to an exwm-mode buffer are said to be local; otherwise, they are global.
An exwm-mode buffer has two input modes: line-mode and char-mode (these phrases are borrowed from ansi-mode ).
They define how key events should be processed. In line-mode , EXWM intercepts all key events and sends applications only
keys not explicitly assigned. Whereas in char-mode , EXWM does no interception but only responds to those globally grabbed
key sequences. exwm-mode buffers are created in line-mode by default. We will discuss how to switch input mode later.
Every exwm-mode buffer also has a major mode menu, from which most commands or other features are accessible. However
it has the limitation that you can not access it from other buffers, so use it as a reference/reminder rather than totally relying on
it.
As a tiling X window manger, EXWM manages X windows in a tiling layout by default. However, if an X window explicitly
requires it, EXWM can alternatively manage it in a floating (or stacking) layout. There are several ways for a user to switch the
layout of an X window, as will be discussed later in this document.
Keybindings
EXWM is a keyboard-driven X window manager, thus it's of great importance to understand key event representations and
learn how to specify/modify key bindings. Fortunately, EXWM uses the same syntax as Emacs itself to denote key events, so
you should feel it quite comfortable to configure it. Besides, it's rather simple to find the representation of a key event by
evaluating (read-key) or (read-event) when you are not sure.
As with Emacs, EXWM uses a key sequence (or key for short) rather than a single key event to make a key binding. Indeed,
key sequences in EXWM are registered to either global or local keymaps just like what is normally done in Emacs; what EXWM
does is to forward those key sequences to Emacs if they are originally intended for other X windows.
One thing worth mentioning is the s- ( Super ) modifier key. Key sequences consisting of this modifier key (or at least some
of them) are usually unusable to Emacs if you are working in other X window managers. However, in EXWM you have full
access to any key sequence (though there might still be some rare exceptions like Ctrl Alt F1 ). The s- modifier key will
be frequently used in this document.
Global key bindings can be defined by customizing exwm-input-global-keys . By default there is no global key biding. Key
bindings in the following table are recommended however:
Switch to line-mode ;
s-r exwm-reset exit fullscreen mode;
refresh layout
(setq exwm-input-global-keys
`(([?\s-r] . exwm-reset)
([?\s-w] . exwm-workspace-switch)
,@(mapcar (lambda (i)
`(,(kbd (format "s-%d" i)) .
(lambda ()
(interactive)
(exwm-workspace-switch-create ,i))))
(number-sequence 0 9))))
When defining local keys prefixed with C-c , you're only allowed to use letters in the remaining of the sequence. Other keys
are considered mode-specific and are reserved for either EXWM or other minor modes. Below is a list of mode-specific keys
currently found in EXWM:
C-c C-t C-f exwm-floating-toggle-floating Toggle between tiling and floating mode
Simulation keys
A simulation key exploits a local key binding to map one key sequence to another and send it to the X window. There are no
predefined simulation keys in EXWM. One may customize exwm-input-simulation-keys to easily define them. One may
also set its value directly:
(setq exwm-input-simulation-keys
'(([?\C-b] . [left])
([?\C-f] . [right])
([?\C-p] . [up])
([?\C-n] . [down])
([?\C-a] . [home])
([?\C-e] . [end])
([?\M-v] . [prior])
([?\C-v] . [next])
([?\C-d] . [delete])
([?\C-k] . [S-end delete])))
This example enables Emacs-like line-editing keys for normal applications. Likewise, one should use e.g. C-c C-q C-v to
send Ctrl v since it's mapped to next ( PgDn ).
Note: Simulation keys are currently sent using SendEvent X requests, so they will not work for a minority of applications.
Some of them can be configured to accept synthetic events however. For example, you can enable the allowSendEvents X
resource of xterm to achieve this.
Simulation keys defined in exwm-input-simulation-keys are shared among all applications. To make this X window-specific,
i.e. buffer-local, exwm-input-set-local-simulation-keys can be used instead. For example, the following lines will disable
simulation keys for Firefox:
(add-hook 'exwm-manage-finish-hook
(lambda ()
(when (and exwm-class-name
(string= exwm-class-name "Firefox"))
(exwm-input-set-local-simulation-keys nil))))
You may change the behaviors by setting the corresponding variables. Be sure to include a button-down event (e.g.
<down-mouse-1> ) in the key sequence to make it sense.
Layout modes
There are three layout modes supported in EXWM, i.e. tiling, floating and (inaccurately) fullscreen.
There is nothing special about the tiling mode. An X window is shown where its underlying buffer is displayed. You can use
C-x b , C-x 1 , C-x 2 , C-x 3 or whatever you normally use to switch buffer / resize Emacs window.
The floating mode is a bit different. An extra Emacs frame is created to hold the X window. By default, a floating X window can
be moved (or resized) by holding s-<down-mouse-1> (or s-<down-mouse-3> ) when dragging the mouse. You can
alternatively move the window with exwm-floating-move or resize it with exwm-layout-{enlarge,shrink}-window[-
horizontally] which by default are not bound.
Note: X windows will automatically be made floating whenever appropriate (e.g. the applications explicitly request), unless
exwm-manage-force-tiling is set to non-nil.
We regard fullscreen as a third layout mode here. An X window in either tiling or floating mode can be made fullscreen explicitly
by invoking C-c C-f . If the X window provides other approaches (typically like pressing F11 or clicking a certain menu
entry), they should also work. One can leave fullscreen mode with the versatile exwm-reset .
Workspace
EXWM supports workspaces and they can be created or removed on-the-fly. EXWM by default creates 1 initial workspace. You
may change the number to e.g. 4 with
(setq exwm-workspace-number 4)
exwm-workspace-switch , when called with no argument, allows you to switch workspace interactively. You will be provided
with a prompt like
where [1] indicates you are currently working in Workspace 1 (the index is zero-based). You may now switch to another
workspace by pressing the corresponding index, or moving [ ] with line-editing keys followed by <return> . exwm-
workspace-switch optionally accepts an argument to directly switch to the target workspace.
Some workspace related commands, such as exwm-workspace-switch , when called interactively provide prompts
including the tag [+/-] . You may then press + to create an empty workspace at the end, or - to remove the selected
workspace.
The command exwm-workspace-switch-create , similar to exwm-workspace-switch , automatically creates missing
workspaces when given an out-of-range index.
The commands exwm-workspace-add / exwm-workspace-delete allow you to add/delete a workspace at a certain
position. When called interactively, exwm-workspace-add adds a workspace at the end (and switch to it), whereas exwm-
workspace-delete deletes the current workspace.
Emacs frame keys (prefixed with C-x 5 ) also provide a way to manage workspaces. However, since there're other kinds
of Emacs frames in EXWM such as those used in floating X windows, be careful not to mess them up.
A workspace can be moved to another position with exwm-workspace-move , and the positions of two workspaces can be
interchanged with exwm-workspace-swap .
Note: EXWM only shows X windows belonging to the current workspace by default. You may alter this behavior by assigning
exwm-workspace-show-all-buffers a non-nil value. Also, you might want to set exwm-layout-show-all-buffers to t to
allow automatically moving X windows from inactive workspaces by switching to their associated buffers.
Note: You are not supposed to move floating X windows when exwm-layout-show-all-buffers is non-nil.
The autohide minibuffer & echo area can be attached back with exwm-workspace-attach-minibuffer , and then detached
again with exwm-workspace-detach-minibuffer .
Note: exwm-workspace-attach-minibuffer requires no dock/panel at the same place to work. For example, if exwm-
workspace-minibuffer-position is set to 'bottom , then there shouldn't be any dock/panel at the bottom of the screen if
you want to attach the autohide minibuffer & echo area.
RandR (multi-screen)
The RandR support is optional and disabled by default. To enable it, add the following code to your .emacs :
(require 'exwm-randr)
(setq exwm-randr-workspace-output-plist '(0 "VGA1"))
(add-hook 'exwm-randr-screen-change-hook
(lambda ()
(start-process-shell-command
"xrandr" nil "xrandr --output VGA1 --left-of LVDS1 --auto")))
(exwm-randr-enable)
The second line actually configures the multiple screens support. The variable exwm-randr-workspace-output-plist is a
property list of the form (workspace-number-1 output-name-1 workspace-number-2 output-name-2 ...) . You can find a
list of output names together with their info by invoking xrandr utility with no argument.
The third line puts output VGA1 on the left of LVDS1 and automatically resizes the screen every time a monitor is
attached/detached. Please refer to xrandr(1) for the detailed usage of xrandr .
If you are looking for an automated behavior to only enable the connected external screen (and automatically revert to the
internal screen after disconnection), here is an example that can be added to exwm-randr-screen-change-hook :
(defun exwm-change-screen-hook ()
(let ((xrandr-output-regexp "\n\\([^ ]+\\) connected ")
default-output)
(with-temp-buffer
(call-process "xrandr" nil t nil)
(goto-char (point-min))
(re-search-forward xrandr-output-regexp nil 'noerror)
(setq default-output (match-string 1))
(forward-line)
(if (not (re-search-forward xrandr-output-regexp nil 'noerror))
(call-process "xrandr" nil nil nil "--output" default-output "--auto")
(call-process
"xrandr" nil nil nil
"--output" (match-string 1) "--primary" "--auto"
"--output" default-output "--off")
(setq exwm-randr-workspace-output-plist (list 0 (match-string 1)))))))
Compositing manager
As of 0.17 EXWM supports third-party compositing managers and the builtin one are no longer provided.
System tray
EXWM provides a simple system tray. It's disabled by default and can be enabled with the following lines:
(require 'exwm-systemtray)
(exwm-systemtray-enable)
EXWM cannot make an X window manager by itself; you must tell X to do it. So first in your ~/.xinitrc , put a line
exec emacs
to launch Emacs when X starts. Alternatively, if you want to run the daemon:
And if you want to leave (exwm-enable) out of your config (which does no harm anyway):
Sometimes you should disable access control by prepending a line to this file if you get a No protocol specified error:
xhost +SI:localuser:$USER
xinit -- vt01
Quitting EXWM is as easy as how you do in Emacs ( C-x C-c perhaps). You can also restart EXWM in place with exwm-
restart .
Appendices
FAQ
1. Make sure you are using the most updated code (including XELB).
2. Check the issues tracker to see whether this has been reported/fixed.
3. Insert the following snippet into your .emacs (comment out the second line if this bug makes Emacs frozen, then use
C-g to quit):
(setq debug-on-error t)
;; (setq debug-on-quit t)
(setq edebug-all-forms t)
4. Turn on exwm-debug minor mode and try to reproduce it. The result would be in the *XELB-DEBUG* buffer. You can use
C-c C-d C-t to toggle debugging, C-c C-d C-m to clear the entire log and C-c C-d C-m to add a mark (^L) for the
current log position.
5. Open an issue with a descriptive title, the bug label selected, and the following contents:
A detailed description of the problem, perhaps with contents from *Backtrace* and *XELB-DEBUG* buffers
Minimal steps to reproduce it
The possible cause of the problem (like some special configuration)
Emacs version, architecture, UI toolkit and system info
X server version ( Xorg -version )
Efficiency? Concurrency?
XELB/EXWM are efficient enough to handle most X11 transactions. They also run concurrently.
You can switch to a TTY and send the signal specified in debug-on-event (defaults to SIGUSR2) to the emacs process. For
instance:
C-c is frequently used in terminal emulators, but since it's by default a prefix key in EXWM, it won't get received by
applications normally. Here are some workarounds:
Configure EXWM to send C-c with C-c C-c . An example for XTerm:
(add-hook 'exwm-manage-finish-hook
(lambda ()
(when (and exwm-class-name
(string= exwm-class-name "XTerm"))
(exwm-input-set-local-simulation-keys '(([?\C-c ?\C-c] . ?\C-c))))))
Note: This approach does not work with Emacs 25 due to a bug of Emacs which is fixed in Emacs 26.2.
You will need to set mouse-autoselect-window and focus-follows-mouse BEFORE loading EXWM, i.e.
(setq mouse-autoselect-window t
focus-follows-mouse t)
[...]
(package-initialize)
[...]
(require 'exwm)
Font size too small on HiDPI displays
This is not an X window manager issue. Please refer to this ArchWiki on how to fix this problem.
Java assumes most WMs reparent X windows. To make Java applications aware that EXWM is a non-reparenting WM, please
add the following line to ~/.xinitrc :
export _JAVA_AWT_WM_NONREPARENTING=1
As with X11, Wayland is also a network protocol and can be implemented as Elisp libraries just like XELB. Indeed, I (@ch11ng)
once made some (unpublished) POC code, but there is very little I can do with it. I turns out it's not possible to implement a
Wayland compositor (server) with pure Elisp; we have to find a workaround.
EXWM does not provide a status bar itself but it is known to run well together with dzen2 or xf-panel.
For dzen, you can put something like this in your .xinitrc :
Alternatively, Emacs has various mode-line / minibuffer monitors, such as the builtins display-time and display-battery-
mode or the symon package.
Known issues
EXWM runs concurrently, but it is only true when the event loop of Emacs is not blocked. However, because Emacs is currently
single-threaded, this seems inevitable in some situations especially when Emacs tries to display some UI widgets:
Widgets such as menus which have OverrideRedirect set may have a chance to work.
Other widgets like dialog boxes probably can not work at all: they would keep waiting for responses from the X window
manager but unfortunately EXWM would have been blocked by that time.
The workaround to this issue is to avoid the use of these features or turn to their text-based alternatives. For instance, most
menus can be accessed through M-` .
This issue occurs with non-floating X windows. If you are used to resize Emacs windows this way, please enable window-
divider-mode as a workaround:
(setq window-divider-default-right-width 1)
(window-divider-mode)
When tooltip-mode is disabled, Emacs displays tooltips on echo area, which again is hard to detect. You're encouraged
to keep tooltip-mode enabled (the default behavior) if you use the autohide minibuffer feature.
When switching to a buffer (not in exwm-mode ) currently displayed on another workspace (frame), ido-mode would raise that
workspace instead of displaying the buffer in the selected Emacs window. This is probably an unwanted behavior and can be
disabled by adding
(exwm-enable-ido-workaround)
to your .emacs .
When in magit, when pressing 'e' to open ediff mode for the selected hunk, magit seems to create a new frame, but instead of
showing something, the screen goes black. From EXWM point of view a new workspace has been created, but it is non-trivial
to go back to the original workspace, because the minibuffer etc. are all missing.
to your .emacs .
Desktop-save-mode does not save on exit
This depends on how you fire up Emacs (e.g. as a daemon). C-x C-c is bound to save-buffers-kill-terminal , which will
exit the client but not the daemon. The latter might be force-killed before it has time to run through all the hooks in kill-
emacs-hook ( desktop-kill among others).
The standard way to close emacs is with C-x C-c ( save-buffers-kill-terminal ). When running exwm with LXDE
however, this does not work since closing emacs does not (AFAIK) allow to close LXDE cleanly. Running lxsession-logout
on the other hand does not give emacs time to cleanly close.
(defun exwm-logout ()
(interactive)
(recentf-save-list)
(save-some-buffers)
(start-process-shell-command "logout" nil "lxsession-logout"))
But:
(defun exwm-logout ()
(interactive)
(bookmark-save)
(recentf-save-list)
(save-some-buffers))
(add anything else you want to it) and then logging out by calling lxsession-logout (by binding it to a 2nd function in emacs
or by any other way you usually run programs in LXDE). This 2 step process assures that emacs has time to complete all
commands properly.
If the only problem is with bookmarks, another option is to simply save bookmarks with M-x bookmark-save or to customize
the variable bookmark-save-flag and use the Arch Linux wiki function. I personally remain worried that some of the
commands may not always successfully complete before logout and prefer the 2 steps method.
Note: I have not tried playing with exwm-exit-hook and do not know whether adding bookmark-save to it would work or
whether the LXDE logout process would still interfere with the command being properly executed.
It has been reported that remapping keys with xcape does not work correctly when using Emac's --with-x-
toolkit=athena toolkit. This can be solved by using other toolkit when building Emacs, for example --with-x-toolkit=no
or --with-x-toolkit=gtk .
Public interfaces
This section contains lists of public interfaces that you might find useful when customizing EXWM. Please refer to their
documentations for more details.
List of commands/functions
exwm-config-default
exwm-config-ido
exwm-config-misc
exwm-enable
exwm-floating-hide
exwm-floating-move
exwm-floating-toggle-floating
exwm-init
exwm-input-grab-keyboard
exwm-input-release-keyboard
exwm-input-send-next-key
exwm-input-send-simulation-key
exwm-input-set-key
exwm-input-set-local-simulation-keys
exwm-input-set-simulation-keys
exwm-input-toggle-keyboard
exwm-layout-enlarge-window
exwm-layout-enlarge-window-horizontally
exwm-layout-hide-mode-line
exwm-layout-set-fullscreen
exwm-layout-show-mode-line
exwm-layout-shrink-window
exwm-layout-shrink-window-horizontally
exwm-layout-toggle-fullscreen
exwm-layout-toggle-mode-line
exwm-layout-unset-fullscreen
exwm-randr-enable
exwm-randr-refresh
exwm-reset
exwm-restart
exwm-systemtray-enable
exwm-workspace-add
exwm-workspace-attach-minibuffer
exwm-workspace-delete
exwm-workspace-detach-minibuffer
exwm-workspace-move
exwm-workspace-move-window
exwm-workspace-rename-buffer
exwm-workspace-swap
exwm-workspace-switch
exwm-workspace-switch-create
exwm-workspace-switch-to-buffer
exwm-workspace-toggle-minibuffer
exwm-xim-enable
exwm-init-hook
exwm-exit-hook
exwm-update-class-hook
exwm-update-title-hook
exwm-blocking-subrs
exwm-floating-setup-hook
exwm-floating-exit-hook
exwm-floating-border-color
exwm-floating-border-width
exwm-input-global-keys
exwm-input-prefix-keys
exwm-input-move-event
exwm-input-resize-event
exwm-input-line-mode-passthrough
exwm-input-simulation-keys
exwm-layout-auto-iconify
exwm-layout-show-all-buffers
exwm-manage-finish-hook
exwm-manage-configurations
exwm-manage-force-tiling
exwm-manage-ping-timeout
exwm-randr-refresh-hook
exwm-randr-screen-change-hook
exwm-randr-workspace-monitor-plist
exwm-systemtray-height
exwm-systemtray-icon-gap
exwm-workspace-switch-hook
exwm-workspace-list-change-hook
exwm-workspace-show-all-buffers
exwm-workspace-number
exwm-workspace-index-map
exwm-workspace-minibuffer-position
exwm-workspace-display-echo-area-timeout
exwm-workspace-switch-create-limit
exwm-workspace-warp-cursor
exwm-mode-map
exwm-workspace-current-index
exwm-class-name
exwm-instance-name
exwm-state
exwm-title
exwm-transient-for
exwm-window-type
Contributing
Both XELB and EXWM are dual-hosted on GitHub and GNU Savannah. GNU Emacs developers may bypass me and make
changes to these projects directly; I will keep both repositories in sync. However, due to copyright issues we cannot accept
significant changes from other developers. If you want to contribute though, you still have several options:
Note that the copyright restriction does not apply to minor changes or modifications of the wiki pages here.
Third-party extensions
Helm-EXWM: Helm sources and functions for browsing and switching to EXWM buffers.
GPastel: The Emacs package gpastel makes sure that every copied text in GPaste is also in the Emacs kill-ring. When
using EXWM (the Emacs X Window Manager), gpastel makes it possible for the user to use the kill-ring from external
applications.
Desktop-environment: This package lets you control your computer with standard keys. For example,
<XF86MonBrightnessUp> raises brightness, <XF86AudioRaiseVolume> raises volume, <print> takes screenshots and
s-l locks your screen.
Changelog
This is a brief record of major changes made to each release.
0.22
What's new:
New exwm-xim module for using Emacs builtin input methods in X windows.
Keep auto-hide echo area displayed when no input is received.
Major fixes:
0.21
What's new:
Major fixes:
0.20
What's new:
Major fixes:
0.19
What's new:
0.18
What's new:
Add support for replacing / being replaced by other window managers. exwm-init and exwm-exit can also be used to
manually start/stop EXWM.
The Customize interface now supports customizing global keys.
Add per-application support for tweaking the initial states of an individual application. It can be accessed via the exwm-
manage-configurations user option.
Mode-specific keys are now enabled by default without the need to add their prefix keys to exwm-input-prefix-keys .
exwm-workspace-switch , exwm-workspace-switch-create , exwm-workspace-move and exwm-workspace-move-
window now support prefix arguments.
Major fixes:
0.17
What's new:
Make EXWM a non-reparenting window manager. As a result third-party compositing managers are now supported and
the built-in one ( exwm-cm ) is thus deprecated.
Add a new Customize interface for accessing most features. It can be accessed via M-x customize RET and then
selecting Applications / EXWM .
Add support for 'focus follows mouse' (requiring mouse-autoselect-window and focus-follows-mouse both being set).
Add support for input-decode-map , local-function-key-map and key-translation-map which can be used for
tweaking line-mode.
Add support for displaying floating X windows on all workspaces (by setting _NET_WM_DESKTOP to 0xffffffff ).
Major fixes:
Pages 7
User Guide
Prerequisites
Installation
Install from GNU ELPA
Install from source
Bootstrap
Conventions
Keybindings
Global key bindings
Local key bindings
Simulation keys
Button-related key bindings
Layout modes
Workspace
X window handling among workspaces
Autohide minibuffer & echo area
(Optional) RandR (multi-screen)
(Optional) Compositing manager
(Optional) System tray
One last thing
Appendices
FAQ
Known issues
Public interfaces
Contributing
Third-party extensions
Changelog
Installation on macOS
Notes to Spacemacs users
Configuration Example
Screenshots
https://github.com/ch11ng/exwm.wiki.git