Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Emacs Window Manager (EXWM) Layer AKA SpacemacsOS #3321

Merged
merged 27 commits into from
Apr 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b67ee4a
Add Emacs Window Manager (EXWM) Layer
CestDiego Oct 9, 2015
87de34f
set window manager name to EXWM
domenzain Aug 9, 2018
1a154f9
update copyright notice
domenzain Aug 9, 2018
fbb6fd9
start server when EXWM is active
domenzain Aug 9, 2018
4b20375
respect Spacemacs naming conventions and layer organization
domenzain Aug 9, 2018
a97ebc6
leave keyboard remapping to users
domenzain Aug 9, 2018
3c99977
add EXWM states for Evil
domenzain Aug 9, 2018
c32e198
add support for helm-exwm when helm is in use
domenzain Aug 9, 2018
c80f4c1
use both exwm-randr and exwm-systemtray
domenzain Aug 9, 2018
083e1e1
set up workspaces to match displays by default
domenzain Aug 9, 2018
36fa796
use ido-config instead of the deprecated workaround
domenzain Aug 9, 2018
6a904ff
add bindings for common X keys
domenzain Aug 9, 2018
a7e449d
use standard prefix commands where available
domenzain Aug 9, 2018
3a9cfe5
remove most keybindings as they are available directly in exwm-state
domenzain Aug 9, 2018
10af17e
enable exwm directly in the layer configuration
domenzain Aug 9, 2018
78e5f77
add user-configurable variables for RandR and workspaces
domenzain Aug 10, 2018
c5e7ab6
fix naming convention for variables
domenzain Aug 10, 2018
f77b3b7
use helm for launching applications when possible
domenzain Aug 10, 2018
d2fda4e
fix conditional helm-exwm leader keys
domenzain Aug 16, 2018
33d772e
remove redundant function
domenzain Aug 17, 2018
227c4c8
conform to naming convention for Spacemacs
domenzain Aug 17, 2018
fefa764
separate prefix commands into those for major mode and global
domenzain Aug 17, 2018
66cfc66
remove all default bindings
domenzain Aug 17, 2018
32125de
improve readability
domenzain Aug 17, 2018
363ab27
clean up bindings
domenzain Aug 17, 2018
5c56f31
remove obsolete comments
domenzain Aug 21, 2018
19568a9
Merge pull request #9 from domenzain/SpacemacsOS
CestDiego Aug 25, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions layers/+window-management/exwm/README.org
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
* EXWM contribution layer for Spacemacs

** Table of Contents :TOC@4:
- [[#exwm-contribution-layer-for-spacemacs][EXWM contribution layer for Spacemacs]]
- [[#description][Description]]
- [[#install][Install]]
- [[#note-about-display-managers][Note about Display Managers]]
- [[#not-having-display-managers][Not having Display Managers]]
- [[#osx][OSX]]
- [[#key-bindings][Key bindings]]

** Description
The time has arrived when one can finally use Emacs as a Window Manager, long
ago the concepts of *windows* and *frames* made so much sense when one was
working in a TTY, and basically that's all the window management you got. In
these *modern* times though, it sounds silly to have those names. But not
Anymore!

Thanks to @ch11ng and his [[https://github.com/ch11ng/exwm][EXWM]] project we can now use Emacs as our window
manager, and all those *windows* that didn't make sense before, now can not only
hold buffers, but X Windows, that means that you can spawn a Browser Window, or
your music player, or anything.

I urge you to read the [[https://github.com/ch11ng/exwm/wiki][EXWM Wiki]] for a more in depth explanation and if you can
contribute, please do so! The purpose of me making this layer is that I find it
awesome and having nice defaults would make more people dive into it and the
project would receive more attention and contributions which will only make it
more awesome, so if you try it and like it, share it!

This is how it looks like:

[[img/spacemacsOS.jpg]]

** Install
To use this contribution add it to your =~/.spacemacs=

#+begin_src emacs-lisp
(setq-default dotspacemacs-configuration-layers '(exwm))
#+end_src

*** Note about Display Managers

This is most common among Ubuntu and derivative users:

LightDM, GDM, and other Display managers that need a session file will need you
to copy the [[file:files/exwm.desktop][desktop file]] I bundled with this layer to
~/usr/local/xsessions/exwm.desktop~, that's what I used on my Ubuntu box, but
make sure the [[file:files/exwm-start][exwm-start script]] is in your PATH, you can put it in
~/usr/local/bin/exwm-start~ and that should be enough, next time you log out,
select the EXWM session instead of the Ubuntu one and you should be alright.

*** Not having Display Managers

If you use Arch, Gentoo, or any other Linux, most probably you'll start your
configurations via a ~.xinitrc~ file, just append ~exwm-start~ to the end of
that file and you should be fine. I do recommend to check the [[https://github.com/ch11ng/exwm/wiki][EXWM Wiki]] for more
details.

*** OSX

If you are an OSX user, please report back on whether this works with xQuartz,
always back up your data before attempting to try stuff like this.

** Key bindings

As other window managers the ~s~ or *Super* key (Windows Key) is the one that
is the prefix to every action. We'll use a lot of ~s~.

I have, for convenience, disabled the use of ~C-x~ and ~C-c~ in X windows,
mainly because that's something we could use for Cutting and Copying text, but if
you want you can enable it, this layer focuses on less Emacs-y bindings.

| Key Binding | Description |
|-----------------------+------------------------------------------------|
| ~C-q~ | Send next key pressed to the X window |
| ~C-'~ | Pop shell |
| ~C-g~ | Universal GetMeOuttaHere Key from Emacs |
| ~C-u~ | Universal Argument |
| ~C-[0-9]~ | Universal Prefix for [0-9] |
| ~M-m~ | Spacemacs Leader Key |
| ~s-[1 2 3 ... 8 9 0]~ | Switch to workspace [1 2 3 ... 8 9 10] |
| ~s-TAB~ | Switch to last workspace |
| ~s-w~ | Workspace Switch Menu (kinda like micro-state) |
| ~s-r~ | Reset window state |
| ~s-SPC~ | App Launcher |
| ~s-ESC~ | Lock Screen |
| ~s-:~ and ~s-;~ | Helm M-x (same as ~SCP :~) |
| ~s-u,U~ | Undo, Redo window configurations |
| ~s-b~ | Show all opened buffers |
| ~s-h,j,k,l~ | Switch to left,lower,upper,right window |
| ~s-H,J,K,L~ | Move window to far left,down,lower,upper,right |
| ~M-s-h,j,k,l~ | Resizing (try them, it's too hard to explain) |
| ~s-[,]~ | Switch to prev,next workspace |
20 changes: 20 additions & 0 deletions layers/+window-management/exwm/config.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
(defvar exwm-terminal-command "xterm"
"Terminal command to run.")

(defvar exwm-locking-command "slock"
"Command to run when locking session")

(defvar exwm-hide-tiling-modeline nil
"Whether to hide modeline.")

(defvar exwm-leader-key nil
"Key to use for EXWM global commands")

(defvar exwm-workspace-switch-wrap t
"Whether `exwm/exwm-workspace-next' and `exwm/exwm-workspace-prev' should wrap.")

(defvar exwm-workspace-number nil
"Number of workspaces. Defaults to the number of connected displays if `nil'.")

(defvar exwm-randr-command nil
"`xrandr' command to set up displays prior to EXWM init.")
14 changes: 14 additions & 0 deletions layers/+window-management/exwm/files/exwm-start
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/sh

# this makes it work in Ubuntu
xhost +
## you might need to append the TTY you are working on
xinit

wmname EXWM

# Set fallback cursor
xsetroot -cursor_name left_ptr

# Finally launch emacs and enable exwm
exec dbus-launch --exit-with-session emacs
5 changes: 5 additions & 0 deletions layers/+window-management/exwm/files/exwm.desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[Desktop Entry]
Name=EXWM
Comment=Emacs Window Manager
Exec=exwm-start
Type=Application
61 changes: 61 additions & 0 deletions layers/+window-management/exwm/funcs.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
(defun exwm/exwm-bind-command (key command &rest bindings)
"Bind KEYs to COMMANDs globally"
(while key
(exwm-input-set-key (kbd key)
`(lambda ()
(interactive)
(start-process-shell-command ,command nil
,command)))
(setq key (pop bindings)
command
(pop bindings))))

(defun exwm/exwm-workspace-next ()
"Switch to next exwm-workspace (to the right)."
(interactive)
(let* ((only-workspace? (equal exwm-workspace-number 1))
(overflow? (= exwm-workspace-current-index (1- exwm-workspace-number))))
(cond
(only-workspace? nil)
(overflow? (when exwm-workspace-switch-wrap
(exwm-workspace-switch 0)))
(t (exwm-workspace-switch (1+ exwm-workspace-current-index))))))

(defun exwm/exwm-workspace-prev ()
"Switch to next exwm-workspace (to the left)."
(interactive)
(let* ((only-workspace? (equal exwm-workspace-number 1))
(overflow? (= exwm-workspace-current-index 0)))
(cond
(only-workspace? nil)
(overflow? (when exwm-workspace-switch-wrap
(exwm-workspace-switch (1- exwm-workspace-number))))
(t (exwm-workspace-switch (1- exwm-workspace-current-index))))))

;; Quick swtiching between workspaces
(defvar exwm--toggle-workspace 0 "Previously selected workspace. Used with `exwm/jump-to-last-exwm'.")

(defun exwm/jump-to-last-exwm ()
(interactive)
(exwm-workspace-switch exwm--toggle-workspace))

(defadvice exwm-workspace-switch
(before save-toggle-workspace activate)
(setq exwm--toggle-workspace exwm-workspace-current-index))

(defun exwm/exwm-app-launcher ()
"Launches an application in your PATH.
Can show completions at point for COMMAND using helm"
(interactive)
(call-interactively
(if (configuration-layer/package-usedp 'helm)
'helm-run-external-command
'async-shell-command)))

(defun exwm/exwm-lock ()
(interactive)
(start-process "" nil exwm-locking-command))

;; Other utilities
(defun exwm//flatenum (i ls)
(if ls (cons i (cons (first ls) (exwm//flatenum (1+ i) (cdr ls)))) (list)))
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
182 changes: 182 additions & 0 deletions layers/+window-management/exwm/packages.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
;;; packages.el --- exwm Layer packages File for Spacemacs
;;
;; Copyright (c) 2012-2014 Sylvain Benner
;; Copyright (c) 2014-2018 Sylvain Benner & Contributors
;;
;; Author: Sylvain Benner <sylvain.benner@gmail.com>
;; URL: https://github.com/syl20bnr/spacemacs
;;
;; This file is not part of GNU Emacs.
;;
;;; License: GPLv3

;; List of all packages to install and/or initialize. Built-in packages
;; which require an initialization must be listed explicitly in the list.
(defconst exwm-packages
'(cl-generic
(helm-exwm :requires helm)
(evil-exwm-state :location (recipe :fetcher github
:repo "domenzain/evil-exwm-state"))
(xelb :location (recipe :fetcher github
:repo "ch11ng/xelb")
:step pre)
(exwm :location (recipe :fetcher github
:repo "ch11ng/exwm")
:step pre)))

(defun exwm/init-helm-exwm ()
;; when helm is used activate extra EXWM features
(use-package helm-exwm
:config
(progn
;; Add EXWM buffers to a specific section in helm mini
(setq exwm-helm-exwm-emacs-buffers-source
(helm-exwm-build-emacs-buffers-source))
(setq exwm-helm-exwm-source (helm-exwm-build-source))
(setq helm-mini-default-sources `(exwm-helm-exwm-emacs-buffers-source
exwm-helm-exwm-source
helm-source-recentf
helm-source-buffer-not-found))
;; Add a prefix command to choose among EXWM buffers only
(spacemacs/set-leader-keys "WW" 'helm-exwm))))

(defun exwm/init-evil-exwm-state ()
(use-package evil-exwm-state
:init
(spacemacs/define-evil-state-face "exwm" "firebrick1")
(spacemacs/define-evil-state-face "exwm-insert" "chartreuse3")))

(defun exwm/init-cl-generic ()
(use-package cl-generic
:demand))

(defun exwm/init-xelb ()
(use-package xelb))

(defun exwm/init-exwm ()
(use-package exwm-randr)
(use-package exwm-systemtray)
(use-package exwm-config)
(use-package exwm
:init
;; Disable dialog boxes since they are unusable in EXWM
(setq use-dialog-box nil)
;; Use as many workspaces as there are connected displays
;; TODO: Is there a way of doing this with xelb?
(defvar exwm--randr-displays (split-string
(shell-command-to-string
"xrandr | grep ' connected' | cut -d' ' -f1 "))
"The list of connected RandR displays")
;; Set at least as many workspaces as there are connected displays.
;; At the user's option, begin with even more workspaces
(setq exwm-workspace-number
(if exwm-workspace-number
(max exwm-workspace-number (list-length exwm--randr-displays))
(list-length exwm--randr-displays)))
;; The first workspaces will match the order in RandR
(setq exwm-randr-workspace-output-plist
(exwm//flatenum 0 exwm--randr-displays))

;; You may want Emacs to show you the time
(display-time-mode t)
(when exwm-hide-tiling-modeline
(add-hook 'exwm-mode-hook #'hidden-mode-line-mode))

:config
(add-hook 'exwm-update-title-hook
(lambda ()
(exwm-workspace-rename-buffer exwm-title)))

(when 'dotspacemacs-use-ido
(exwm-config-ido)
;; Only rename windows intelligently when using ido.
;; When using helm-exwm, the source distinguishes title and class.
(add-hook 'exwm-update-class-hook
(lambda ()
(unless (or (string-prefix-p "sun-awt-X11-" exwm-instance-name)
(string= "gimp" exwm-instance-name))
(exwm-workspace-rename-buffer exwm-class-name))))
(add-hook 'exwm-update-title-hook
(lambda ()
(when (or (not exwm-instance-name)
(string-prefix-p "sun-awt-X11-" exwm-instance-name)
(string= "gimp" exwm-instance-name))
(exwm-workspace-rename-buffer exwm-title)))))

;; Remove ALL bindings
(define-key exwm-mode-map "\C-c\C-f" nil)
(define-key exwm-mode-map "\C-c\C-h" nil)
(define-key exwm-mode-map "\C-c\C-k" nil)
(define-key exwm-mode-map "\C-c\C-m" nil)
(define-key exwm-mode-map "\C-c\C-q" nil)
(define-key exwm-mode-map "\C-c\C-t\C-f" nil)
(define-key exwm-mode-map "\C-c\C-t\C-m" nil)
;; Let easy-menu figure out the keys
(easy-menu-add-item exwm-mode-menu '()
["Toggle mode-line" exwm-layout-toggle-mode-line])
(easy-menu-add-item exwm-mode-menu '()
["Move X window to" exwm-workspace-move-window])

(exwm/exwm-bind-command
"s-'" exwm-terminal-command
"<s-return>" exwm-terminal-command
"<XF86MonBrightnessUp>" "light -A 5"
"<XF86MonBrightnessDown>" "light -U 5"
"<XF86AudioLowerVolume>" "amixer -D pulse -- sset Master unmute 3%-"
"<XF86AudioRaiseVolume>" "amixer -D pulse -- sset Master unmute 3%+"
"<XF86AudioMute>" "amixer -D pulse -- sset Master toggle"
"<XF86AudioMicMute>" "amixer -D pulse -- sset Capture toggle")

;; Pass all keypresses to emacs in line mode.
(setq exwm-input-line-mode-passthrough t)


;; `exwm-input-set-key' allows you to set a global key binding (available in
;; any case). Following are a few examples.

(exwm-input-set-key (kbd "s-i") 'exwm-input-toggle-keyboard)
(exwm-input-set-key (kbd "M-m") 'spacemacs-cmds)
(exwm-input-set-key (kbd "C-q") 'exwm-input-send-next-key)
;; + We always need a way to go back to line-mode from char-mode
(exwm-input-set-key (kbd "s-r") 'exwm-reset)

(exwm-input-set-key (kbd "s-f") #'exwm/exwm-layout-toggle-fullscreen)
(exwm-input-set-key (kbd "<s-tab>") #'exwm/jump-to-last-exwm)
;; + Bind a key to switch workspace interactively
(exwm-input-set-key (kbd "s-w") 'exwm-workspace-switch)
(exwm-input-set-key (kbd "s-SPC") #'exwm/exwm-app-launcher)
(exwm-input-set-key (kbd "s-l") 'exwm/exwm-lock)

;; set up evil escape
(exwm-input-set-key [escape] 'evil-escape)

;; Bindings available everywhere
(spacemacs/declare-prefix "W" "EXWM")
(spacemacs/set-leader-keys
"Wp" 'exwm/exwm-workspace-prev
"Wn" 'exwm/exwm-workspace-next
"WA" 'exwm-workspace-add
"Wd" 'exwm-workspace-delete
"Wr" 'exwm-restart
"Wl" 'exwm/exwm-lock
"Wa" 'exwm/exwm-app-launcher)

;; Bindings for use only on EXWM buffers
(spacemacs/declare-prefix-for-mode 'exwm-mode
"mT" "toggle")
(spacemacs/set-leader-keys-for-major-mode 'exwm-mode
"r" 'exwm-reset
"Tf" 'exwm-layout-toggle-fullscreen
"Tt" 'exwm-floating-toggle-floating
"Tm" 'exwm-layout-toggle-mode-line)

(exwm-randr-enable)
(exwm-systemtray-enable)

(if exwm-randr-command
(start-process-shell-command
"xrandr" nil exwm-randr-command))

(exwm-init)
(server-start)
))