2019-12-14 14:23:20 +01:00
|
|
|
|
;; -*- lexical-binding: t; -*-
|
|
|
|
|
;;
|
|
|
|
|
;; Configure desktop environment settings, including both
|
|
|
|
|
;; window-management (EXWM) as well as additional system-wide
|
|
|
|
|
;; commands.
|
|
|
|
|
|
|
|
|
|
(require 'dash)
|
|
|
|
|
(require 'exwm)
|
|
|
|
|
(require 'exwm-config)
|
|
|
|
|
(require 'exwm-randr)
|
|
|
|
|
(require 'exwm-systemtray)
|
2021-12-24 20:28:22 +01:00
|
|
|
|
(require 'exwm-xim )
|
|
|
|
|
(require 'f)
|
|
|
|
|
(require 's)
|
2019-12-14 14:23:20 +01:00
|
|
|
|
|
2021-03-23 21:30:29 +01:00
|
|
|
|
(defcustom tazjin--screen-lock-command "tazjin-screen-lock"
|
|
|
|
|
"Command to execute for locking the screen."
|
|
|
|
|
:group 'tazjin)
|
|
|
|
|
|
|
|
|
|
(defcustom tazjin--backlight-increase-command "light -A 4"
|
|
|
|
|
"Command to increase screen brightness."
|
|
|
|
|
:group 'tazjin)
|
|
|
|
|
|
|
|
|
|
(defcustom tazjin--backlight-decrease-command "light -U 4"
|
|
|
|
|
"Command to decrease screen brightness."
|
|
|
|
|
:group 'tazjin)
|
|
|
|
|
|
2019-12-14 14:23:20 +01:00
|
|
|
|
(defun pactl (cmd)
|
|
|
|
|
(shell-command (concat "pactl " cmd))
|
|
|
|
|
(message "Volume command: %s" cmd))
|
|
|
|
|
|
|
|
|
|
(defun volume-mute () (interactive) (pactl "set-sink-mute @DEFAULT_SINK@ toggle"))
|
|
|
|
|
(defun volume-up () (interactive) (pactl "set-sink-volume @DEFAULT_SINK@ +5%"))
|
|
|
|
|
(defun volume-down () (interactive) (pactl "set-sink-volume @DEFAULT_SINK@ -5%"))
|
|
|
|
|
|
|
|
|
|
(defun brightness-up ()
|
|
|
|
|
(interactive)
|
2021-03-23 21:30:29 +01:00
|
|
|
|
(shell-command tazjin--backlight-increase-command)
|
2019-12-14 14:23:20 +01:00
|
|
|
|
(message "Brightness increased"))
|
|
|
|
|
|
|
|
|
|
(defun brightness-down ()
|
|
|
|
|
(interactive)
|
2021-03-23 21:30:29 +01:00
|
|
|
|
(shell-command tazjin--backlight-decrease-command)
|
2019-12-14 14:23:20 +01:00
|
|
|
|
(message "Brightness decreased"))
|
|
|
|
|
|
2021-01-19 15:49:16 +01:00
|
|
|
|
(defun set-xkb-layout (layout)
|
|
|
|
|
"Set the current X keyboard layout."
|
|
|
|
|
|
|
|
|
|
(shell-command (format "setxkbmap %s" layout))
|
|
|
|
|
(shell-command "setxkbmap -option caps:super")
|
|
|
|
|
(message "Set X11 keyboard layout to '%s'" layout))
|
|
|
|
|
|
2019-12-14 14:23:20 +01:00
|
|
|
|
(defun lock-screen ()
|
|
|
|
|
(interactive)
|
2021-01-19 15:49:16 +01:00
|
|
|
|
(set-xkb-layout "us")
|
2021-12-24 20:28:22 +01:00
|
|
|
|
(deactivate-input-method)
|
2021-03-23 21:30:29 +01:00
|
|
|
|
(shell-command tazjin--screen-lock-command))
|
2019-12-14 14:23:20 +01:00
|
|
|
|
|
|
|
|
|
(defun create-window-name ()
|
|
|
|
|
"Construct window names to be used for EXWM buffers by
|
|
|
|
|
inspecting the window's X11 class and title.
|
|
|
|
|
|
|
|
|
|
A lot of commonly used applications either create titles that
|
|
|
|
|
are too long by default, or in the case of web
|
|
|
|
|
applications (such as Cider) end up being constructed in
|
|
|
|
|
awkward ways.
|
|
|
|
|
|
|
|
|
|
To avoid this issue, some rewrite rules are applied for more
|
|
|
|
|
human-accessible titles."
|
|
|
|
|
|
|
|
|
|
(pcase (list (or exwm-class-name "unknown") (or exwm-title "unknown"))
|
|
|
|
|
;; In Cider windows, rename the class and keep the workspace/file
|
|
|
|
|
;; as the title.
|
|
|
|
|
(`("Google-chrome" ,(and (pred (lambda (title) (s-ends-with? " - Cider" title))) title))
|
|
|
|
|
(format "Cider<%s>" (s-chop-suffix " - Cider" title)))
|
2021-08-06 13:04:56 +02:00
|
|
|
|
(`("Google-chrome" ,(and (pred (lambda (title) (s-ends-with? " - Cider V" title))) title))
|
|
|
|
|
(format "Cider V<%s>" (s-chop-suffix " - Cider V" title)))
|
2019-12-14 14:23:20 +01:00
|
|
|
|
|
|
|
|
|
;; Attempt to detect IRCCloud windows via their title, which is a
|
|
|
|
|
;; combination of the channel name and network.
|
|
|
|
|
;;
|
|
|
|
|
;; This is what would often be referred to as a "hack". The regexp
|
|
|
|
|
;; will not work if a network connection buffer is selected in
|
|
|
|
|
;; IRCCloud, but since the title contains no other indication that
|
|
|
|
|
;; we're dealing with an IRCCloud window
|
|
|
|
|
(`("Google-chrome"
|
|
|
|
|
,(and (pred (lambda (title)
|
|
|
|
|
(s-matches? "^[\*\+]\s#[a-zA-Z0-9/\-]+\s\|\s[a-zA-Z\.]+$" title)))
|
|
|
|
|
title))
|
|
|
|
|
(format "IRCCloud<%s>" title))
|
|
|
|
|
|
|
|
|
|
;; For other Chrome windows, make the title shorter.
|
|
|
|
|
(`("Google-chrome" ,title)
|
|
|
|
|
(format "Chrome<%s>" (s-truncate 42 (s-chop-suffix " - Google Chrome" title))))
|
|
|
|
|
|
|
|
|
|
;; Gnome-terminal -> Term
|
|
|
|
|
(`("Gnome-terminal" ,title)
|
|
|
|
|
;; fish-shell buffers contain some unnecessary whitespace and
|
|
|
|
|
;; such before the current working directory. This can be
|
|
|
|
|
;; stripped since most of my terminals are fish shells anyways.
|
|
|
|
|
(format "Term<%s>" (s-trim-left (s-chop-prefix "fish" title))))
|
|
|
|
|
|
2020-09-09 12:26:21 +02:00
|
|
|
|
;; Quassel buffers
|
|
|
|
|
;;
|
|
|
|
|
;; These have a title format that looks like:
|
2021-05-23 21:27:17 +02:00
|
|
|
|
;; "Quassel IRC - #tvl (hackint) — Quassel IRC"
|
2020-09-09 12:26:21 +02:00
|
|
|
|
(`("quassel" ,title)
|
|
|
|
|
(progn
|
2020-09-14 14:12:33 +02:00
|
|
|
|
(if (string-match
|
|
|
|
|
(rx "Quassel IRC - "
|
|
|
|
|
(group (one-or-more (any alnum "[" "]" "&" "-" "#"))) ;; <-- channel name
|
|
|
|
|
" (" (group (one-or-more (any ascii space))) ")" ;; <-- network name
|
|
|
|
|
" — Quassel IRC")
|
|
|
|
|
title)
|
|
|
|
|
(format "Quassel<%s>" (match-string 2 title))
|
|
|
|
|
title)))
|
2020-09-09 12:26:21 +02:00
|
|
|
|
|
2019-12-14 14:23:20 +01:00
|
|
|
|
;; For any other application, a name is constructed from the
|
|
|
|
|
;; window's class and name.
|
|
|
|
|
(`(,class ,title) (format "%s<%s>" class (s-truncate 12 title)))))
|
|
|
|
|
|
|
|
|
|
;; EXWM launch configuration
|
|
|
|
|
;;
|
|
|
|
|
;; This used to use use-package, but when something breaks use-package
|
|
|
|
|
;; it doesn't exactly make debugging any easier.
|
|
|
|
|
|
|
|
|
|
(let ((titlef (lambda ()
|
|
|
|
|
(exwm-workspace-rename-buffer (create-window-name)))))
|
|
|
|
|
(add-hook 'exwm-update-class-hook titlef)
|
|
|
|
|
(add-hook 'exwm-update-title-hook titlef))
|
|
|
|
|
|
|
|
|
|
(fringe-mode 3)
|
|
|
|
|
(exwm-enable)
|
|
|
|
|
|
2022-02-07 19:55:00 +01:00
|
|
|
|
;; Create 10 EXWM workspaces
|
2019-12-14 14:23:20 +01:00
|
|
|
|
(setq exwm-workspace-number 10)
|
2022-02-07 19:55:00 +01:00
|
|
|
|
|
|
|
|
|
;; 's-N': Switch to certain workspace, but switch back to the previous
|
|
|
|
|
;; one when tapping twice (emulates i3's `back_and_forth' feature)
|
|
|
|
|
(defvar *exwm-workspace-from-to* '(-1 . -1))
|
|
|
|
|
(defun exwm-workspace-switch-back-and-forth (target-idx)
|
|
|
|
|
;; If the current workspace is the one we last jumped to, and we are
|
|
|
|
|
;; asked to jump to it again, set the target back to the previous
|
|
|
|
|
;; one.
|
|
|
|
|
(when (and (eq exwm-workspace-current-index (cdr *exwm-workspace-from-to*))
|
|
|
|
|
(eq target-idx exwm-workspace-current-index))
|
|
|
|
|
(setq target-idx (car *exwm-workspace-from-to*)))
|
|
|
|
|
|
|
|
|
|
(setq *exwm-workspace-from-to*
|
|
|
|
|
(cons exwm-workspace-current-index target-idx))
|
|
|
|
|
|
|
|
|
|
(exwm-workspace-switch-create target-idx))
|
|
|
|
|
|
2019-12-14 14:23:20 +01:00
|
|
|
|
(dotimes (i 10)
|
|
|
|
|
(exwm-input-set-key (kbd (format "s-%d" i))
|
|
|
|
|
`(lambda ()
|
|
|
|
|
(interactive)
|
2022-02-07 19:55:00 +01:00
|
|
|
|
(exwm-workspace-switch-back-and-forth ,i))))
|
2019-12-14 14:23:20 +01:00
|
|
|
|
|
2022-02-07 19:27:50 +01:00
|
|
|
|
;; Implement MRU functionality for EXWM workspaces, making it possible
|
|
|
|
|
;; to jump to the previous/next workspace very easily.
|
|
|
|
|
(defvar *recent-workspaces* nil
|
|
|
|
|
"List of the most recently used EXWM workspaces.")
|
|
|
|
|
|
|
|
|
|
(defvar *workspace-jumping-to* nil
|
|
|
|
|
"What offset in the workspace history are we jumping to?")
|
|
|
|
|
|
|
|
|
|
(defvar *workspace-history-position* 0
|
|
|
|
|
"Where in the workspace history are we right now?")
|
|
|
|
|
|
|
|
|
|
(defun update-recent-workspaces ()
|
|
|
|
|
"Hook to run on every workspace switch which will prepend the new
|
|
|
|
|
workspace to the MRU list, unless we are already on that
|
|
|
|
|
workspace. Does not affect the MRU list if a jump is
|
|
|
|
|
in-progress."
|
|
|
|
|
|
|
|
|
|
(if *workspace-jumping-to*
|
|
|
|
|
(setq *workspace-history-position* *workspace-jumping-to*
|
|
|
|
|
*workspace-jumping-to* nil)
|
|
|
|
|
|
|
|
|
|
;; reset the history position to the front on a normal jump
|
|
|
|
|
(setq *workspace-history-position* 0)
|
|
|
|
|
|
|
|
|
|
(unless (eq exwm-workspace-current-index (car *recent-workspaces*))
|
|
|
|
|
(setq *recent-workspaces* (cons exwm-workspace-current-index
|
|
|
|
|
(-take 9 *recent-workspaces*))))))
|
|
|
|
|
|
|
|
|
|
(add-to-list 'exwm-workspace-switch-hook #'update-recent-workspaces)
|
|
|
|
|
|
|
|
|
|
(defun switch-to-previous-workspace ()
|
|
|
|
|
"Switch to the previous workspace in the MRU workspace list."
|
|
|
|
|
(interactive)
|
|
|
|
|
|
|
|
|
|
(let* (;; the previous workspace is one position further down in the
|
|
|
|
|
;; workspace history
|
|
|
|
|
(position (+ *workspace-history-position* 1))
|
|
|
|
|
(target-idx (elt *recent-workspaces* position)))
|
|
|
|
|
(if (not target-idx)
|
|
|
|
|
(message "No previous workspace in history!")
|
|
|
|
|
|
|
|
|
|
(setq *workspace-jumping-to* position)
|
|
|
|
|
(exwm-workspace-switch target-idx))))
|
|
|
|
|
|
|
|
|
|
(exwm-input-set-key (kbd "s-b") #'switch-to-previous-workspace)
|
|
|
|
|
|
|
|
|
|
(defun switch-to-next-workspace ()
|
|
|
|
|
"Switch to the next workspace in the MRU workspace list."
|
|
|
|
|
(interactive)
|
|
|
|
|
|
|
|
|
|
(if (<= *workspace-history-position* 1)
|
|
|
|
|
(message "No next workspace in history!")
|
|
|
|
|
(let* (;; The next workspace is one position further up in the
|
|
|
|
|
;; history. This always exists unless someone messed with
|
|
|
|
|
;; it.
|
|
|
|
|
(position (- *workspace-history-position* 1))
|
|
|
|
|
(target-idx (elt *recent-workspaces* position)))
|
|
|
|
|
(setq *workspace-jumping-to* position)
|
|
|
|
|
(exwm-workspace-switch target-idx))))
|
|
|
|
|
|
|
|
|
|
(exwm-input-set-key (kbd "s-f") #'switch-to-next-workspace)
|
|
|
|
|
|
2020-12-09 14:57:25 +01:00
|
|
|
|
;; Launch applications / any command with completion (dmenu style!)
|
2019-12-14 14:23:20 +01:00
|
|
|
|
(exwm-input-set-key (kbd "s-d") #'counsel-linux-app)
|
2020-12-09 14:57:25 +01:00
|
|
|
|
(exwm-input-set-key (kbd "s-x") #'run-external-command)
|
|
|
|
|
(exwm-input-set-key (kbd "s-p") #'password-store-lookup)
|
2019-12-14 14:23:20 +01:00
|
|
|
|
|
|
|
|
|
;; Add X11 terminal selector to a key
|
2019-12-15 23:54:40 +01:00
|
|
|
|
(exwm-input-set-key (kbd "C-x t") #'ts/switch-to-terminal)
|
2019-12-14 14:23:20 +01:00
|
|
|
|
|
|
|
|
|
;; Toggle between line-mode / char-mode
|
|
|
|
|
(exwm-input-set-key (kbd "C-c C-t C-t") #'exwm-input-toggle-keyboard)
|
|
|
|
|
|
|
|
|
|
;; Volume keys
|
|
|
|
|
(exwm-input-set-key (kbd "<XF86AudioMute>") #'volume-mute)
|
|
|
|
|
(exwm-input-set-key (kbd "<XF86AudioRaiseVolume>") #'volume-up)
|
|
|
|
|
(exwm-input-set-key (kbd "<XF86AudioLowerVolume>") #'volume-down)
|
|
|
|
|
|
|
|
|
|
;; Brightness keys
|
|
|
|
|
(exwm-input-set-key (kbd "<XF86MonBrightnessDown>") #'brightness-down)
|
|
|
|
|
(exwm-input-set-key (kbd "<XF86MonBrightnessUp>") #'brightness-up)
|
|
|
|
|
(exwm-input-set-key (kbd "<XF86Display>") #'lock-screen)
|
|
|
|
|
|
2020-05-16 04:54:44 +02:00
|
|
|
|
;; Shortcuts for switching between keyboard layouts
|
|
|
|
|
(defmacro bind-xkb (lang key)
|
|
|
|
|
`(exwm-input-set-key (kbd (format "s-%s" ,key))
|
|
|
|
|
(lambda ()
|
|
|
|
|
(interactive)
|
|
|
|
|
(set-xkb-layout ,lang))))
|
|
|
|
|
|
|
|
|
|
(bind-xkb "us" "k u")
|
|
|
|
|
(bind-xkb "de" "k d")
|
|
|
|
|
(bind-xkb "no" "k n")
|
|
|
|
|
(bind-xkb "ru" "k r")
|
2020-09-24 13:15:11 +02:00
|
|
|
|
(bind-xkb "se" "k s")
|
2020-05-16 04:54:44 +02:00
|
|
|
|
|
|
|
|
|
;; These are commented out because Emacs no longer starts (??) if
|
|
|
|
|
;; they're set at launch.
|
|
|
|
|
;;
|
2021-06-23 20:14:35 +02:00
|
|
|
|
(bind-xkb "us" "л г")
|
|
|
|
|
(bind-xkb "de" "л в")
|
|
|
|
|
(bind-xkb "no" "л т")
|
|
|
|
|
(bind-xkb "ru" "л к")
|
2019-12-14 14:23:20 +01:00
|
|
|
|
|
2021-12-24 20:28:22 +01:00
|
|
|
|
;; Configuration of EXWM input method handling for X applications
|
|
|
|
|
(exwm-xim-enable)
|
|
|
|
|
(setq default-input-method "russian-computer")
|
|
|
|
|
(push ?\C-\\ exwm-input-prefix-keys)
|
|
|
|
|
|
2019-12-14 14:23:20 +01:00
|
|
|
|
;; Line-editing shortcuts
|
|
|
|
|
(exwm-input-set-simulation-keys
|
|
|
|
|
'(([?\C-d] . delete)
|
|
|
|
|
([?\C-w] . ?\C-c)))
|
|
|
|
|
|
|
|
|
|
;; Show time & battery status in the mode line
|
|
|
|
|
(display-time-mode)
|
|
|
|
|
(display-battery-mode)
|
|
|
|
|
|
|
|
|
|
;; enable display of X11 system tray within Emacs
|
|
|
|
|
(exwm-systemtray-enable)
|
|
|
|
|
|
2020-04-17 14:12:26 +02:00
|
|
|
|
;; Configure xrandr (multi-monitor setup).
|
|
|
|
|
|
|
|
|
|
(defun set-randr-config (screens)
|
|
|
|
|
(setq exwm-randr-workspace-monitor-plist
|
|
|
|
|
(-flatten (-map (lambda (screen)
|
|
|
|
|
(-map (lambda (screen-id) (list screen-id (car screen))) (cdr screen)))
|
|
|
|
|
screens))))
|
|
|
|
|
|
2021-10-27 08:42:02 +02:00
|
|
|
|
;; Layouts for Tverskoy (X13 AMD laptop)
|
|
|
|
|
(defun randr-tverskoy-layout-single ()
|
2020-04-17 14:12:26 +02:00
|
|
|
|
"Laptop screen only!"
|
|
|
|
|
(interactive)
|
2021-10-27 08:42:02 +02:00
|
|
|
|
(set-randr-config '(("eDP" (number-sequence 0 9))))
|
|
|
|
|
(shell-command "xrandr --output eDP --auto --primary")
|
|
|
|
|
(shell-command "xrandr --output HDMI-A-0 --off")
|
2020-04-17 14:12:26 +02:00
|
|
|
|
(exwm-randr-refresh))
|
|
|
|
|
|
2021-10-27 08:42:02 +02:00
|
|
|
|
(defun randr-tverskoy-split-workspace ()
|
2021-11-13 17:43:46 +01:00
|
|
|
|
"Split the workspace across two screens, assuming external to the left."
|
2021-06-23 20:15:12 +02:00
|
|
|
|
(interactive)
|
|
|
|
|
(set-randr-config
|
2021-11-13 17:43:46 +01:00
|
|
|
|
'(("HDMI-A-0" 1 2 3 4 5 6 7)
|
|
|
|
|
("eDP" 8 9 0)))
|
2021-06-23 20:15:12 +02:00
|
|
|
|
|
2021-11-13 17:43:46 +01:00
|
|
|
|
(shell-command "xrandr --output HDMI-A-0 --left-of eDP --auto")
|
2021-06-23 20:15:12 +02:00
|
|
|
|
(exwm-randr-refresh))
|
|
|
|
|
|
2020-06-12 01:14:24 +02:00
|
|
|
|
;; Layouts for frog (desktop)
|
2020-04-18 16:27:56 +02:00
|
|
|
|
|
2020-06-12 01:14:24 +02:00
|
|
|
|
(defun randr-frog-layout-right-only ()
|
|
|
|
|
"Use only the right screen on frog."
|
2020-04-18 16:27:56 +02:00
|
|
|
|
(interactive)
|
2020-06-24 03:23:59 +02:00
|
|
|
|
(set-randr-config `(("DisplayPort-0" ,(number-sequence 0 9))))
|
2020-07-21 21:14:14 +02:00
|
|
|
|
(shell-command "xrandr --output DisplayPort-0 --off")
|
|
|
|
|
(shell-command "xrandr --output DisplayPort-1 --auto --primary"))
|
2020-04-18 16:27:56 +02:00
|
|
|
|
|
2020-06-12 01:14:24 +02:00
|
|
|
|
(defun randr-frog-layout-both ()
|
|
|
|
|
"Use the left and right screen on frog."
|
2020-04-18 16:27:56 +02:00
|
|
|
|
(interactive)
|
2020-07-21 21:14:14 +02:00
|
|
|
|
(set-randr-config `(("DisplayPort-0" 1 2 3 4 5)
|
|
|
|
|
("DisplayPort-1" 6 7 8 9 0)))
|
2020-04-18 16:27:56 +02:00
|
|
|
|
|
2020-07-21 21:14:14 +02:00
|
|
|
|
(shell-command "xrandr --output DisplayPort-0 --auto --primary --left-of DisplayPort-1")
|
|
|
|
|
(shell-command "xrandr --output DisplayPort-1 --auto --right-of DisplayPort-0 --rotate left"))
|
2020-04-18 16:27:56 +02:00
|
|
|
|
|
|
|
|
|
(pcase (s-trim (shell-command-to-string "hostname"))
|
2021-10-27 08:42:02 +02:00
|
|
|
|
("tverskoy"
|
|
|
|
|
(exwm-input-set-key (kbd "s-m s") #'randr-tverskoy-layout-single)
|
|
|
|
|
(exwm-input-set-key (kbd "s-m 2") #'randr-tverskoy-split-workspace))
|
2019-12-14 14:23:20 +01:00
|
|
|
|
|
2020-06-12 01:14:24 +02:00
|
|
|
|
("frog"
|
|
|
|
|
(exwm-input-set-key (kbd "s-m b") #'randr-frog-layout-both)
|
|
|
|
|
(exwm-input-set-key (kbd "s-m r") #'randr-frog-layout-right-only)))
|
2020-04-18 16:27:56 +02:00
|
|
|
|
|
2020-12-20 17:26:10 +01:00
|
|
|
|
;; Notmuch shortcuts as EXWM globals
|
|
|
|
|
;; (g m => gmail)
|
|
|
|
|
(exwm-input-set-key (kbd "s-g m") #'notmuch)
|
|
|
|
|
(exwm-input-set-key (kbd "s-g M") #'counsel-notmuch)
|
|
|
|
|
|
2020-04-18 16:27:56 +02:00
|
|
|
|
(exwm-randr-enable)
|
2020-04-17 14:12:26 +02:00
|
|
|
|
|
2019-12-14 14:23:20 +01:00
|
|
|
|
;; Let buffers move seamlessly between workspaces by making them
|
|
|
|
|
;; accessible in selectors on all frames.
|
|
|
|
|
(setq exwm-workspace-show-all-buffers t)
|
|
|
|
|
(setq exwm-layout-show-all-buffers t)
|
|
|
|
|
|
|
|
|
|
(provide 'desktop)
|