Pierre Neidhardt edited this page Jun 20, 2017 · 63 revisions

EXWM User Guide

This guide serves as an introduction for new users to EXWM as well as a reference for advanced users. It mainly discusses major conceptions, usage and configurations of EXWM. It will be updated accordingly as EXWM evolves. Please consider helping improve this document.

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 enviromments (e.g. LXDE) with EXWM. Most contents in this document still apply there.


There's no specific prerequisite indeed. But if there have to be some, here they are (should be easily satisfied):

  • GNU Emacs with version higher than 24.4, 25 preferred. Also GTK+3 and 64-bit build is preferred. You should probably hide menu-bar, tool-bar, scroll-bar etc to work in EXWM or it would be quite weird.
  • X11 server (a recent version please).


Install from GNU ELPA

To install EXWM and all its dependencies, simply invoke M-x package-install RET exwm RET.

Install from source

You should first checkout the code of XELB and EXWM, then add their source directories to load-path like:

(add-to-list 'load-path "/path/to/xelb/")
(add-to-list 'load-path "/path/to/exwm/")

Note: Emacs 24 users should install the cl-generic package from GNU ELPA as well.


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.

  1. Add following lines to your .emacs:

    (require 'exwm)
    (require 'exwm-config)
  2. Link or copy xinitrc (from source directory) to ~/.xinitrc.

  3. Start EXWM from a console (e.g. tty1) with

    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.


This section discusses some conventions which you should make clear before going through the rest of this document.

Note: All configuration code should be put in your .emacs (rather than evaluated after EXWM has finished starting) unless otherwise specified. Also don't forget to put (exwm-enable) there to actually enable EXWM.

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.


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

Global key bindings are available in both line-mode and char-mode. They even work in normal buffers; take this into account when you make a global key binding.

There is no global key bindings predefined in EXWM by default, but you can easily make one with exwm-input-set-key which works precisely like global-set-key. Key bindings in the following table are recommended but again, not bound by default.

Key Command Remark
s-r exwm-reset Switch to line-mode;
exit fullscreen mode;
refresh layout
s-w exwm-workspace-switch Interactively switch workspace
s-N (exwm-workspace-switch N) Switch to workspace N (N is a digit)

Local key bindings

Local key bindings are only available in line-mode. The only way to make a local key binding is to modify exwm-mode-map with e.g. define-key. You may have to add the prefix key (first key) of the key sequence to exwm-input-prefix-keys if the prefix key is not already there, e.g.

(push ?\C-q exwm-input-prefix-keys)
(define-key exwm-mode-map [?\C-q] 'exwm-input-send-next-key)

Prefix keys defined in exwm-input-prefix-keys are shared among all applications. You may modify the local binding of exwm-input-prefix-keys to change prefix keys for one specific applications. For instance, the following lines will set C-c as the only prefix key for Firefox (so you can use keys like C-x normally there):

(add-hook 'exwm-manage-finish-hook
          (lambda ()
            (when (and exwm-class-name
                       (string= exwm-class-name "Firefox"))
              (setq-local exwm-input-prefix-keys '(?\C-c)))))

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:

Key Command Remark
C-c C-f exwm-layout-set-fullscreen Enter fullscreen mode
C-c C-h exwm-floating-hide Hide a floating X window
C-c C-k exwm-input-release-keyboard Switch to char-mode
C-c C-m exwm-workspace-move-window Move X window to another workspace
C-c C-q exwm-input-send-next-key Send a single key to the X window;
can be prefixed with C-u to send multiple keys
C-c C-t C-f exwm-floating-toggle-floating Toggle between tiling and floating mode
C-c C-t C-m exwm-layout-toggle-mode-line Toggle mode-line

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 use exwm-input-set-simulation-keys to easily define them, e.g.

 '(([?\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 with exwm-input-set-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))))

Button-related key bindings

Button-related key bindings are only used when moving/resizing an X window. Currently there are only two such use cases:

Key Variable Remark
s-<down-mouse-1> exwm-input-move-event Move X window
s-<down-mouse-3> exwm-input-resize-event Resize X window

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.


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

Switch to [+/-]: 0 [1] 2  3 

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.

There're several ways to add and/or remove workspaces:

  • 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 toexwm-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 be mess up them.

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.

X window handling among workspaces

An X window can be moved to another workspace with C-c C-m, or exwm-workspace-move-window. An X window on another workspace can be bring to the current one with exwm-workspace-switch-to-buffer.

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.

Autohide minibuffer & echo area

As with normal Emacs frames, the minibuffer and echo area (sharing the same mini-window) are fixed at the bottom of each workspace by default. They can be detached and automatically shown/hidden/resized by setting exwm-workspace-minibuffer-position to either 'bottom or 'top, which indicates the position of the minibuffer & echo area when they appear. The minibuffer is shown when it's entered and hidden when exited. The echo area is shown there're new messages and hidden after a certain amount of time, which is controled by exwm-workspace-display-echo-area-timeout (in seconds).

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 ()
             "xrandr" nil "xrandr --output VGA1 --left-of LVDS1 --auto")))

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.

Compositing manager

A compositing manager is responsible for providing visual effects such as transparency. In X11 a compositing manager is most often a window manager with the compositing functionality built-in. There're also some standalone solutions designed for working with lightweight window managers. But since EXWM does not (and probably will never) work with any of these, a compositing manager module is provided. This module is optional and is disabled by default. To use it, add the following lines to your .emacs.

(require 'exwm-cm)
;; Make all Emacs frames opaque.
(setq window-system-default-frame-alist '((x . ((alpha . 100)))))
;; Assign everything else a 80% opacity.
(setq exwm-cm-opacity 80)

You can comment out the last line and start/stop the compositing manager with exwm-cm-start / exwm-cm-stop (or exwm-cm-toggle) instead. The opacity of an X window can be modified with exwm-cm-set-opacity, otherwise it'll fall back to use the value of exwm-cm-opacity. The opacity of Emacs frames (workspace frames, floating frames, etc) can be modified with the alpha frame parameter; this can be done either by setting window-system-default-frame-alist just like the example above, or by calling set-frame-parameter at any time. If the alpha frame parameter is not set, the opacity of frames will also use the value of exwm-cm-opacity.

Note: Some utilities for setting opacity might not be used here, since they won't set the value on the correct X window.

System tray

EXWM provides a simple system tray. It's disabled by default and can be enabled with the following lines:

(require 'exwm-systemtray)

Note: The system tray is displayed on active workspace only.

One last thing

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. 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

Then EXWM can be launched in console with

xinit -- vt01

where vt01 indicates you are starting X from tty1.

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.



How to report a bug?

  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. If not, try to reproduce it use a source (rather than byte-compiled) installation with the following code in your .emacs (add it before loading XELB/EXWM; 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)
    (setq exwm-debug-on t)
  4. 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 *Messages* buffers
    • Minimal steps to reproduce it
    • The cause of the problem if you have find it out
    • Emacs version, architecture, UI toolkit; system / X server info

Efficiency? Concurrency?

XELB/EXWM are efficient enough to handle most X11 transactions. They also run concurrently.

How to send C-c to *Term*?

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:

  • Use ansi-term instead.

  • Work with terminal emulators in char-mode.

  • Use exwm-input-send-next-key (bound to C-c C-q by default) to send C-c.

    Note: See also Simulation keys for the note on XTerm.

  • Remove C-c from prefix keys (you should make sure there's no simulation keys prefixed with C-c). As a side-effect, all mode-specific keys won't be accessible from the keyboard. An example for XTerm:

    (add-hook 'exwm-manage-finish-hook
              (lambda ()
                (when (and exwm-class-name
                           (string= exwm-class-name "XTerm"))
                  (setq-local exwm-input-prefix-keys '(?\C-x)))))
  • 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.

    Note: See also Simulation keys for the note on XTerm.

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.

Will there be a Wayland port?

Perhaps, but Emacs itself should have a Wayland port first.

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.

Known issues

Issues caused by the single-threaded nature of Emacs

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-`.

Unable to resize an X window by dragging its right edge

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)

Minor issues related to the autohide echo area

The autohide echo area can not be activated in certain circumstances:

  • Emacs by default echoes keystrokes on echo area on slow input. There seems to be no way to detect such behavior so the autohide echo area feature may cause problems for some users. You can disable keystroke echoing by setting echo-keystrokes to 0.
  • 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.

Note you can always use exwm-workspace-attach-minibuffer and exwm-workspace-detach-minibuffer to temporarily pin the echo area (and also the minibuffer).

An issue with ido-mode

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


to your .emacs.

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-cm-enable
  • exwm-cm-set-opacity
  • exwm-cm-start
  • exwm-cm-stop
  • exwm-cm-toggle
  • exwm-config-default
  • exwm-config-ido
  • 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-show-mode-line
  • exwm-layout-shrink-window
  • exwm-layout-shrink-window-horizontally
  • exwm-layout-set-fullscreen
  • exwm-layout-toggle-fullscreen
  • exwm-layout-toggle-mode-line
  • exwm-layout-unset-fullscreen
  • exwm-randr-enable
  • 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

List of hooks

  • exwm-floating-exit-hook
  • exwm-floating-setup-hook
  • exwm-init-hook
  • exwm-manage-finish-hook
  • exwm-randr-refresh-hook
  • exwm-randr-screen-change-hook
  • exwm-update-class-hook
  • exwm-update-title-hook
  • exwm-workspace-list-change-hook
  • exwm-workspace-switch-hook

List of global variables

  • exwm-blocking-subrs
  • exwm-cm-opacity
  • exwm-debug-on (should be set before loading EXWM)
  • exwm-floating-border-color
  • exwm-floating-border-width
  • exwm-input-move-event
  • exwm-input-resize-event
  • exwm-layout-show-all-buffers
  • exwm-manage-force-tiling
  • exwm-manage-ping-timeout
  • exwm-mode-map
  • exwm-input-line-mode-passthrough
  • exwm-input-prefix-keys
  • exwm-randr-workspace-output-plist
  • exwm-systemtray-height
  • exwm-systemtray-icon-gap
  • exwm-workspace-current-index
  • exwm-workspace-display-echo-area-timeout
  • exwm-workspace-minibuffer-position
  • exwm-workspace-number
  • exwm-workspace-show-all-buffers
  • exwm-workspace-switch-create-limit

List of buffer-local variables

  • exwm-class-name
  • exwm-instance-name
  • exwm-state
  • exwm-title
  • exwm-transient-for
  • exwm-window-type


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:

  • Complete the copyright assignment paperwork and become a GNU contributor.
  • Instead of implementing a feature, you may introduce the idea.
  • You might as well present a draft implementation so that we'll reimplement it later.

Note that the copyright restriction does not apply to minor changes or modifications of the wiki pages here.