Browse Source

Split desktop module

main
parent
commit
7b908c0854
  1. 20
      elisp/options.el
  2. 33
      modules/dap.org
  3. 187
      modules/desktop.org
  4. 44
      modules/docker.org
  5. 71
      modules/exwm.org
  6. 18
      modules/gpg.org
  7. 76
      modules/lsp.org
  8. 14
      modules/pass.org
  9. 165
      modules/x11.org

20
elisp/options.el

@ -1,19 +1,11 @@
(defconst dotfiles/modules-p (defconst dotfiles/modules-p
'(org trash
keys evil dired magit
shell
mu4e
elfeed
eshell vterm
passwords pinentry
desktop
roam agenda spelling grammar
reveal hugo
capture
projects
'(org trash keys evil dired magit
shell mu4e elfeed eshell vterm
gpg pass x11 exwm roam agenda
spelling grammar reveal hugo
capture projects docker lsp dap
development development
fonts ivy themes modeline
dashboard)
fonts ivy themes modeline dashboard)
"All of the available modules.") "All of the available modules.")
(defvar dotfiles/modules dotfiles/modules-p (defvar dotfiles/modules dotfiles/modules-p

33
modules/dap.org

@ -0,0 +1,33 @@
#+TITLE: Debug Adapter Protocol
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle dap.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
The Debug Adapter Protocol (DAP) defines the abstract protocol used between a development tool (Emacs) and a debugger[fn:1].
* Config
Use the package ~dap-mode~[fn:2] to add support for the Debug Adapter Protocol[fn:1] inside of Emacs. It has been tested against the following language servers:
+ Java
+ Ruby
+ Python
+ Elixir
+ LLDB (C/C++/Obj-C/Swift)
#+begin_src emacs-lisp
(use-package dap-mode
:commands (dap-debug))
#+end_src
* Footnotes
[fn:1] https://microsoft.github.io/debug-adapter-protocol/
[fn:2] https://github.com/emacs-lsp/dap-mode

187
modules/desktop.org

@ -1,187 +0,0 @@
#+TITLE: Desktop
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle desktop.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
#+ATTR_ORG: :width 420px
#+ATTR_HTML: :width 420px
#+ATTR_LATEX: :width 420px
[[../docs/images/desktop-example.png]]
I use Emacs as a Desktop Environment with the *EXWM*[fn:1] package. It allows Emacs to function as a complete tiling window manager for *X11*[fn:2].
* Initialization
:PROPERTIES:
:header-args: :tangle ../config/xinitrc :comments org
:END:
My workflow includes launching the window manager with *Xinit*[fn:3], without the use of a display manager, controlling *everything* within Emacs. In addition, compton is used as a display compositor, and slock for a screen lock.
#+begin_src conf
compton &
xss-lock -- slock &
# FIXME! https://github.com/ch11ng/exwm/issues/210#issuecomment-350044271
exec dbus-launch --exit-with-session emacs -mm --debug-init
#+end_src
** Create a symbolic link(s)
*Xinit*[fn:3] reads its configuration from ~~/.xinitrc~. Override this location with a link to the custom configuration.
#+begin_src emacs-lisp
(dotfiles/symlink "~/.emacs.d/config/xinitrc"
"~/.xinitrc")
#+end_src
** Desktop environment
Use the *desktop-environment* package to automatically bind well-known programs for controlling the volume, brightness, media playback, and many other XF86 functionality bindings.
#+begin_src emacs-lisp
(use-package desktop-environment
:after exwm
:custom (desktop-environment-brightness-small-increment "2%+")
(desktop-environment-brightness-small-decrement "2%-")
(desktop-environment-brightness-normal-decrement "5%-")
(desktop-environment-brightness-normal-decrement "5%-")
(desktop-environment-volume-small-increment "2%+")
(desktop-environment-volume-small-decrement "2%-")
(desktop-environment-volume-normal-increment "5%+")
(desktop-environment-volume-normal-decrement "5%-")
:config (desktop-environment-mode))
#+end_src
** Keyboard tweaks
:PROPERTIES:
:header-args: conf :tangle ../config/xmodmap
:END:
Use *XModmap* to swap CapsLock and Ctrl to keep common bindings on the home row.
#+begin_src conf
clear lock
clear control
keycode 66 = Control_L
add control = Control_L
add Lock = Control_R
#+end_src
#+begin_src emacs-lisp
(dotfiles/symlink "~/.emacs.d/config/xmodmap"
"~/.Xmodmap")
#+end_src
#+RESULTS:
* Displays detection
When the window manager first launches the ~init-hook~ executes, allowing us to define some custom logic.
+ Display time and date
+ Display battery info (if available)
In my personal configuration, I do not want the battery or time displayed within Emacs when it's not running as desktop environment because that information is typically already available.
#+begin_src emacs-lisp
(defun dotfiles/init-hook ()
(exwm-workspace-switch-create 1)
(setq display-time-and-date t)
(display-battery-mode 1)
(display-time-mode 1))
#+end_src
Using =autorandr= with pre configured profiles, switching screens (AKA hot plugging) is also handled through a hook.
#+begin_src emacs-lisp
(defun dotfiles/update-display ()
"Update the displays by forcing a change through autorandr."
(dotfiles/run-in-background "autorandr --change --force"))
#+end_src
* Window manager
Connect our custom hooks and configure the input keys, a custom layer for key capture layers.
+ Enable =randr= support
+ Pass through to Emacs
+ =M-x= to Emacs
+ =C-g= to Emacs
+ =C-SPC= to Emacs
+ Bindings with =S= (Super / Win)
+ Reset =S-r=
+ Launch =S-&=
+ Workspace =S-[1..9]=
#+begin_src emacs-lisp
(use-package exwm
:when (window-system)
:custom (exwm-workspace-show-all-buffers t)
(exwm-input-prefix-keys
'(?\M-x
?\C-g
?\C-\ ))
(exwm-input-global-keys
`(([?\s-r] . exwm-reset)
,@(mapcar (lambda (i)
`(,(kbd (format "s-%d" i)) .
(lambda ()
(interactive)
(exwm-workspace-switch-create ,i))))
(number-sequence 1 9))))
:config (require 'exwm-randr)
(exwm-randr-enable)
(add-hook 'exwm-init-hook #'dotfiles/init-hook)
(add-hook 'exwm-randr-screen-change-hook #'dotfiles/update-display)
(add-hook 'exwm-update-class-hook (lambda () (exwm-workspace-rename-buffer exwm-class-name)))
(dotfiles/update-display)
(dotfiles/run-in-background "nitrogen --restore") ;; Update the wallpaper.
(exwm-enable))
#+end_src
* Frame transparency
TODO
#+begin_src emacs-lisp
(defun dotfiles/toggle-transparency ()
(interactive)
(let ((alpha (frame-parameter nil 'alpha)))
(set-frame-parameter nil 'alpha
(if (eql (cond ((numberp alpha) alpha)
((numberp (cdr alpha)) (cdr alpha))
((numberp (cadr alpha)) (cadr alpha)))
100)
'(85 . 50) '(100 . 100)))))
#+end_src
Toggle frame transparency with =SPC t r=.
#+begin_src emacs-lisp
(dotfiles/leader
"tr" '(dotfiles/toggle-transparency :which-key "Toggle transparency"))
#+end_src
Enable frame transparency by default.
#+begin_src emacs-lisp
(set-frame-parameter (selected-frame) 'alpha '(85 . 50))
(add-to-list 'default-frame-alist '(alpha . (85 . 50)))
#+end_src
* Footnotes
[fn:1] https://github.com/ch11ng/exwm
[fn:2] https://en.wikipedia.org/wiki/X_Window_System
[fn:3] https://en.wikipedia.org/wiki/Xinit
[fn:4] https://wiki.termux.com/wiki/Graphical_Environment

44
modules/docker.org

@ -0,0 +1,44 @@
#+TITLE: Docker
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle docker.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Interact with Docker[fn:1] inside of Emacs.
* Setup
Make sure you have the required components installed on your system before loading the module.
#+begin_src shell
RUN apt install -y docker docker-compose
#+end_src
* Config
It's possible to interact with Docker[fn:1] inside of Emacs through the ~docker.el~[fn:2] plugin. It provides rich support for working with containers, images, compose networks, and has bindings for using machine.
#+begin_src emacs-lisp
(use-package docker
:commands (docker))
#+end_src
* Shortcuts
Open the container management screen with =SPC k=.
#+begin_src emacs-lisp
(dotfiles/leader
"k" '(docker :which-key "Docker"))
#+end_src
* Footnotes
[fn:1] https://docker.com
[fn:2] https://github.com/Silex/docker.el

71
modules/exwm.org

@ -0,0 +1,71 @@
#+TITLE: EXWM
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle exwm.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Emacs can run as a complete tiling window manager for X11.
* Setup
Load the ~x11~ module before loading this module.
* Config
When ~exwm~[fn:1] first launches the ~init-hook~ is executed, allowing us to define some custom logic inside of a hook. Display the time and date, and the battery information, if any is available. I add this here because when I'm running Emacs without ~exwm~[fn:1], information such as the batter and time is typically already available.
#+begin_src emacs-lisp
(defun dotfiles/init-hook ()
(exwm-workspace-switch-create 1)
(setq display-time-and-date t)
(display-battery-mode 1)
(display-time-mode 1))
#+end_src
** Display detection
Enable hot plugging by forcing a profile change with ~autorandr~.
#+begin_src emacs-lisp
(defun dotfiles/update-display ()
"Update the displays by forcing a change through autorandr."
(dotfiles/run-in-background "autorandr --change --force"))
#+end_src
** Window manager
Connect all of the custom hooks and configure the input keys, a custom layer for key captures when Emacs us running as a window manager. Enable ~randr~ support, to function with ~autorandr~, and apply some default bindings.
#+begin_src emacs-lisp
(use-package exwm
:when (window-system)
:custom (exwm-workspace-show-all-buffers t)
(exwm-input-prefix-keys
'(?\M-x
?\C-g
?\C-\ ))
(exwm-input-global-keys
`(([?\s-r] . exwm-reset)
,@(mapcar (lambda (i)
`(,(kbd (format "s-%d" i)) .
(lambda ()
(interactive)
(exwm-workspace-switch-create ,i))))
(number-sequence 1 9))))
:config (require 'exwm-randr)
(exwm-randr-enable)
(add-hook 'exwm-init-hook #'dotfiles/init-hook)
(add-hook 'exwm-randr-screen-change-hook #'dotfiles/update-display)
(add-hook 'exwm-update-class-hook (lambda () (exwm-workspace-rename-buffer exwm-class-name)))
(dotfiles/update-display)
(dotfiles/run-in-background "nitrogen --restore") ;; Update the wallpaper.
(exwm-enable))
#+end_src
* Footnotes
[fn:1] https://github.com/ch11ng/exwm

18
modules/pinentry.org → modules/gpg.org

@ -1,29 +1,29 @@
#+TITLE: Pinentry
#+TITLE: GPG
#+AUTHOR: Christopher James Hayward #+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz #+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle pinentry.el :comments org
#+PROPERTY: header-args:emacs-lisp :tangle gpg.el :comments org
#+PROPERTY: header-args:shell :tangle no #+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org #+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil #+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil #+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Handle GPG pinentry within Emacs.
Handle GPG[fn:1] pinentry within Emacs.
* Setup * Setup
:PROPERTIES: :PROPERTIES:
:header-args: :tangle ../config/gpg-agent.conf :header-args: :tangle ../config/gpg-agent.conf
:END: :END:
When the ~gpg-agent~ loads it will read the configuration at =~/.gnupg/gpg-agent.conf=. Override the default settings to allow Emacs to function as the Pinentry application.
When the ~gpg-agent~[fn:1] loads it will read the configuration at =~/.gnupg/gpg-agent.conf=. Override the default settings to allow Emacs to function as the Pinentry application.
#+begin_src conf #+begin_src conf
allow-emacs-pinentry allow-emacs-pinentry
allow-loopback-pinentry allow-loopback-pinentry
#+end_src #+end_src
You may need to restart the ~gpg-agent~ to load the configuration without rebooting.
You may need to restart the ~gpg-agent~[fn:1] to load the configuration without rebooting.
#+begin_src shell :tangle nil #+begin_src shell :tangle nil
gpgconf --reload gpg-agent gpgconf --reload gpg-agent
@ -38,7 +38,7 @@ Create the symbolic link to the configuration file.
"~/.gnupg/gpg-agent.conf") "~/.gnupg/gpg-agent.conf")
#+end_src #+end_src
With the ~pinentry~ package for Emacs prompts will now appear in the minibuffer. Increase the minimum prime bit size to increase performance during symmetric encryption.
With the ~pinentry~[fn:2] package for Emacs prompts will now appear in the minibuffer. Increase the minimum prime bit size to increase performance during symmetric encryption.
#+begin_src emacs-lisp #+begin_src emacs-lisp
(use-package pinentry (use-package pinentry
@ -50,6 +50,8 @@ With the ~pinentry~ package for Emacs prompts will now appear in the minibuffer.
:config (pinentry-start)) :config (pinentry-start))
#+end_src #+end_src
** Including agenda files
Override ~org-agenda-file-regexp~ to include =.org.gpg= files. Override ~org-agenda-file-regexp~ to include =.org.gpg= files.
#+begin_src emacs-lisp #+begin_src emacs-lisp
@ -60,3 +62,7 @@ Override ~org-agenda-file-regexp~ to include =.org.gpg= files.
#+end_src #+end_src
* Footnotes * Footnotes
[fn:1] https://gnupg.org
[fn:2] https://elpa.gnu.org/packages/pinentry.html

76
modules/lsp.org

@ -0,0 +1,76 @@
#+TITLE: Language Server Protocol
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle lsp.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
The Language Server Protocol (LSP) defines the protocol used between an editor, or IDE, and a language server that provides language features like auto-complete, go-to-definition, find-all-references, etc[fn:1]
* Config
Support for the Language Server Protocol[fn:1] is available through the ~lsp-mode~[fn:2] package. Configure an immutable delay of =.5= to ensure it doesn't attack the current language server and overload it with requests.
#+begin_src emacs-lisp
(use-package lsp-mode
:commands (lsp lsp-deferred)
:custom (lsp-idle-delay 0.5)
(lsp-prefer-flymake t))
#+end_src
** Code snippets
Download ~yasnippet~[fn:4], used by a number of ~lsp-mode~[fn:2] extensions to provide smart completion functionality.
#+begin_src emacs-lisp
(use-package yasnippet
:ensure t)
#+end_src
** UI integration
Download ~lsp-ui~[fn:3] to provide user interface improvements for ~lsp-mode~[fn:2] over the defaults.
#+begin_src emacs-lisp
(use-package lsp-ui
:after lsp
:custom (lsp-ui-doc-position 'at-point)
(lsp-ui-doc-delay 0.500))
#+end_src
** Code completion
Text completion provided by ~company~[fn:5], AKA Complete Anything. Make sure it's integrated with ~lsp-mode~[fn:2] to provide completion candidates through the Language Server Protocol[fn:1].
#+begin_src emacs-lisp
(use-package company
:after lsp)
#+end_src
Specify the repository for ~company-lsp~ using straight to make sure we're getting the most recent version from GitHub, instead of the typically outdated versions in the Emacs package repositories.
#+begin_src emacs-lisp
(use-package company-lsp
:after (lsp company)
:custom (company-lsp-async t)
(company-backend 'company-lsp)
:straight (company-lsp :type git
:host github
:repo "tigersoldier/company-lsp"))
#+end_src
* Footnotes
[fn:1] https://microsoft.github.io/language-server-protocol/
[fn:2] https://emacs-lsp.github.io/lsp-mode/
[fn:3] https://emacs-lsp.github.io/lsp-ui/
[fn:4] https://github.com/joaotavora/yasnippet
[fn:5] https://company-mode.github.io/

14
modules/passwords.org → modules/pass.org

@ -1,8 +1,8 @@
#+TITLE: Passwords
#+TITLE: Pass
#+AUTHOR: Christopher James Hayward #+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz #+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle passwords.el :comments org
#+PROPERTY: header-args:emacs-lisp :tangle pass.el :comments org
#+PROPERTY: header-args:shell :tangle no #+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org #+PROPERTY: header-args :results silent :eval no-export :comments org
@ -13,15 +13,15 @@ Password management inside of Emacs.
* Setup * Setup
Install ~pass~ on the system.
Install ~pass~[fn:1] on the system before loading the module.
#+begin_src shell #+begin_src shell
RUN apt install pass
RUN apt install -y pass
#+end_src #+end_src
* Config * Config
Encrypted passwords are stored inside files, in a file structure providing easy commands for generating, modifying, and copying passwords. ~password-store.el~ provides a wrapper for the functionality within Emacs.
Encrypted passwords are stored inside files, in a file structure providing easy commands for generating, modifying, and copying passwords. ~password-store.el~[fn:2] provides a wrapper for the functionality within Emacs.
#+begin_src emacs-lisp #+begin_src emacs-lisp
(use-package password-store (use-package password-store
@ -45,3 +45,7 @@ Configure keybindings behind =SPC p=:
#+end_src #+end_src
* Footnotes * Footnotes
[fn:1] https://passwordstore.org
[fn:2] https://github.com/NicolasPetton/pass

165
modules/x11.org

@ -0,0 +1,165 @@
#+TITLE: X11
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle x11.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
X11[fn:1] is a graphical display manager.
* Setup
Install the required software on your system before loading the module. Installing X11[fn:1] without any install recommends may not include all of the packages you need on your system. Make sure you don't need any GNOME software utilities before using this example.
#+begin_src shell
RUN apt install -y xserver-xorg-core \
--no-install-recommends \
--no-install-suggests
#+end_src
** Displays
Setup ~autorandr~[fn:2] with pre-configured profiles for screen size and display output.
#+begin_src shell
RUN apt install autorandr -y
#+end_src
** Screen locking
If you want to be able to lock and unlock your screen when you're away from your machine, install ~xss-lock~[fn:3]. By default, it will show a blue screen, turning red if you input your password incorrectly, and returning to your previous screen when successful.
#+begin_src shell
RUN apt install -y xss-lock slock
#+end_src
** Desktop compositor
Download and install ~compton~[fn:4], a desktop compositor for X11[fn:1] that adds shadows, fading, translucency, and implements window frame opacity controls, inactive window transparency, and more.
#+begin_src shell
RUN apt install -y compton
#+end_src
** Desktop notifications
Make sure ~dbus~[fn:5] is installed to receive desktop notifications, it's an IPC system used by lots of utilities.
#+begin_src shell
RUN apt install -y dbus
#+end_src
* Config
:PROPERTIES:
:header-args: :tangle ../config/xinitrc :comments org
:END:
My workflow includes launching Emacs under X11[fn:1] without the use of a display manager, controlling everything within Emacs, while still providing the functionality of a desktop environment.
#+begin_src conf
compton &
xss-lock -- slock &
exec dbus-launch --exit-with-session emacs -mm --debug-init
#+end_src
** Create symbolic link
By default ~xinit~[fn:1] will read the configuration file at =$HOME/.xinitrc=. Override this location with a link to the custom configuration.
#+begin_src emacs-lisp
(dotfiles/symlink "~/.emacs.d/config/xinitrc"
"~/.xinitrc")
#+end_src
** Desktop environment
Use the ~desktop-environment~[fn:6] package to automatically bind well-known programs for controlling the volume, brightness, media playback, and many other XF86 functionality bindings.
#+begin_src emacs-lisp
(use-package desktop-environment
:after exwm
:custom (desktop-environment-brightness-small-increment "2%+")
(desktop-environment-brightness-small-decrement "2%-")
(desktop-environment-brightness-normal-decrement "5%-")
(desktop-environment-brightness-normal-decrement "5%-")
(desktop-environment-volume-small-increment "2%+")
(desktop-environment-volume-small-decrement "2%-")
(desktop-environment-volume-normal-increment "5%+")
(desktop-environment-volume-normal-decrement "5%-")
:config (desktop-environment-mode))
#+end_src
** Swapping CAPS and CTRL
:PROPERTIES:
:header-args: conf :tangle ../config/xmodmap
:END:
Use ~Xmodmap~[fn:7] to swap CapsLock and Ctrl to keep common bindings on the home row.
#+begin_src conf
clear lock
clear control
keycode 66 = Control_L
add control = Control_L
add Lock = Control_R
#+end_src
Override the configuration file.
#+begin_src emacs-lisp
(dotfiles/symlink "~/.emacs.d/config/xmodmap"
"~/.Xmodmap")
#+end_src
** Frame transparency
Emacs supports frame transparency when running under the X Window System[fn:1].
#+begin_src emacs-lisp
(defun dotfiles/toggle-transparency ()
(interactive)
(let ((alpha (frame-parameter nil 'alpha)))
(set-frame-parameter nil 'alpha
(if (eql (cond ((numberp alpha) alpha)
((numberp (cdr alpha)) (cdr alpha))
((numberp (cadr alpha)) (cadr alpha)))
100)
'(85 . 50) '(100 . 100)))))
#+end_src
Enable frame transparency by default.
#+begin_src emacs-lisp
(set-frame-parameter (selected-frame) 'alpha '(85 . 50))
(add-to-list 'default-frame-alist '(alpha . (85 . 50)))
#+end_src
* Shortcuts
Toggle frame transparency with =SPC t r=.
#+begin_src emacs-lisp
(dotfiles/leader
"tr" '(dotfiles/toggle-transparency :which-key "Toggle transparency"))
#+end_src
* Footnotes
[fn:1] https://en.wikipedia.org/wiki/X_Window_System
[fn:2] https://github.com/phillipberndt/autorandr
[fn:3] https://man.archlinux.org/man/xss-lock.1
[fn:4] https://github.com/chjj/compton
[fn:5] https://packages.debian.org/stretch/dbus-x11
[fn:6] https://github.com/DamienCassou/desktop-environment
[fn:7] https://wiki.archlinux.org/title/Xmodmap
Loading…
Cancel
Save