diff options
-rw-r--r-- | emacs | 34 | ||||
-rw-r--r-- | emacs.d/elisp/exwm-mff.el | 191 | ||||
-rw-r--r-- | shrc | 4 |
3 files changed, 216 insertions, 13 deletions
@@ -29,7 +29,10 @@ x-select-enable-clipboard t x-select-enable-primary t ring-bell-function 'ignore - + default-directory (concat (getenv "HOME") "/") + focus-follows-mouse t + mouse-autoselect-window t + ;; Backups backup-by-copying t delete-old-versions t @@ -53,6 +56,7 @@ yasnippet yasnippet-snippets pinentry + eat avy tldr elfeed @@ -66,7 +70,7 @@ package-archives '(("elpa" . "https://elpa.gnu.org") ("gnu" . "http://elpa.gnu.org/packages/") ("melpa" . "https://melpa.org/packages/") - ("non-gnu" . "https://elpa.nongnu.org/nongnu") + ("non-gnu" . "https://elpa.nongnu.org/nongnu/") ("melpa-stable" . "https://stable.melpa.org/packages/"))) (setq-default fill-column 80 @@ -122,12 +126,15 @@ (interactive) (exwm-workspace-switch-create ,i)))) (number-sequence 0 9)))) + (exwm-input-set-key (kbd "s-f") + (lambda () (interactive) + (shell-command "firefox"))) (exwm-input-set-key (kbd "<print>") (lambda () (interactive) (shell-command "scrot -F '/home/mccd/screenshots/%Y-%m-%d_$wx$h.png'"))) (exwm-input-set-key (kbd "C-<print>") (lambda () (interactive) - (shell-command "scrot -s -F '/home/mccd/screenshots/%Y-%m-%d_$wx$h.png'"))) + (shell-command "scrot -s -F '/home/mccd/screenshots/%Y-%m-%d_$wx$h.png'"))) (exwm-enable) (exwm-xim-mode) (push ?\C-\\ exwm-input-prefix-keys) @@ -162,6 +169,10 @@ (setq epa-pinentry-mode 'loopback)) +(use-package exwm-mff + :load-path "elisp" + :init + (exwm-mff-mode)) (use-package avy :ensure t @@ -306,8 +317,6 @@ (defvar marcc/timestamp-format "%H:%M " "Format for H:M timestamp") - - (defun marcc/timestamp-hour () "Insert a timestamp at the current point. Uses `marcc/timestamp-format' for formatting the date/time." @@ -321,8 +330,10 @@ Uses `marcc/timestamp-format' for formatting the date/time." :hook ((diary-mode . variable-pitch-mode) (diary-fancy-display-mode . variable-pitch-mode) - (diary-mode . org-link-minor-mode) - (diary-fancy-display-mode . org-link-minor-mode) + (diary-mode . 'org-link-minor-mode) + (diary-fancy-display-mode . 'org-link-minor-mode) + (diary-mode . (lambda () + (add-hook 'after-save-hook 'sync-org))) (diary-mode . flyspell-mode)) :config (global-set-key (kbd "C-c d") 'calendar) @@ -385,7 +396,8 @@ Uses `marcc/timestamp-format' for formatting the date/time." (defun sync-org () (interactive) - (shell-command "org-sync")) + (async-shell-command "org-sync")) +(add-to-list 'display-buffer-alist '("*Async Shell Command*" display-buffer-no-window (nil))) ;; Org (use-package org @@ -442,6 +454,8 @@ Uses `marcc/timestamp-format' for formatting the date/time." (org-mode . org-indent-mode) (org-mode . flyspell-mode) (org-mode . visual-line-mode) + (org-mode . (lambda () + (add-hook 'after-save-hook 'sync-org))) (org-mode . variable-pitch-mode))) (use-package rec-mode @@ -681,10 +695,10 @@ Uses `marcc/timestamp-format' for formatting the date/time." '((:name "Last 7 days" :query "date:7d..now" :hide-unread t :key 119) (:name "Messages with images" :query "mime:image/*" :key 112))) '(org-agenda-files - '("~/personal-db/notes/reminders.org" "/home/mccd/builds/sustainably/piva.org" "/home/mccd/personal-db/notes/programming.org" "/home/mccd/personal-db/notes/unix.org" "/home/mccd/personal-db/notes/sustainable-software.org" "/home/mccd/personal-db/notes/agency-and-tech.org" "/home/mccd/personal-db/notes/carving-my-own-road.org" "/home/mccd/personal-db/notes/emacs-teaches.org" "/home/mccd/personal-db/notes/emacs.org" "/home/mccd/personal-db/notes/inbox.org" "/home/mccd/personal-db/notes/todo.org")) + '("/home/mccd/personal-db/notes/ethics-and-software.org" "/home/mccd/personal-db/notes/reminders.org" "/home/mccd/builds/sustainably/piva.org" "/home/mccd/personal-db/notes/programming.org" "/home/mccd/personal-db/notes/unix.org" "/home/mccd/personal-db/notes/sustainable-software.org" "/home/mccd/personal-db/notes/agency-and-tech.org" "/home/mccd/personal-db/notes/emacs-teaches.org" "/home/mccd/personal-db/notes/emacs.org" "/home/mccd/personal-db/notes/inbox.org" "/home/mccd/personal-db/notes/todo.org")) '(org-fold-core-style 'overlays) '(package-selected-packages - '(pinentry exwm emms company orglink web-mode flycheck nix-mode nix-ts-mode avy pdf-tools elfeed-protocol lem yasnippet-snippets elfeed yasnippet smartparens markdown-mode mastodon tldr almost-mono-themes rec-mode magit go-mode expand-region devdocs)) + '(exwm-mff eat pinentry exwm emms company orglink web-mode flycheck nix-mode nix-ts-mode avy pdf-tools elfeed-protocol lem yasnippet-snippets elfeed yasnippet smartparens markdown-mode mastodon tldr almost-mono-themes rec-mode magit go-mode expand-region devdocs)) '(tab-bar-format '(tab-bar-format-align-right tab-bar-format-global)) '(yank-from-kill-ring-rotate t)) (put 'secrets-mode 'disabled nil) diff --git a/emacs.d/elisp/exwm-mff.el b/emacs.d/elisp/exwm-mff.el new file mode 100644 index 0000000..6b1ef87 --- /dev/null +++ b/emacs.d/elisp/exwm-mff.el @@ -0,0 +1,191 @@ +;;; exwm-mff.el --- Mouse Follows Focus -*- lexical-binding: t; -*- + +;; Copyright (C) 2019, 2020, 2021 Ian Eure + +;; Author: Ian Eure <public@lowbar.fyi> +;; URL: https://github.com/ieure/exwm-mff +;; Version: 1.2.1 +;; Package-Requires: ((emacs "25.1")) +;; Keywords: unix + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Mouse Follows Focus +;; =================== +;; +;; Traditional window managers are mouse-centric: the window to receive +;; input is usually selected with the pointing device. +;; +;; Emacs is keybord-centric: the window to receive key input is usually +;; selected with the keyboard. When you use the keyboard to focus a +;; window, the spatial relationship between pointer and active window is +;; broken -- the pointer can be anywhere on the screen, instead of over +;; the active window, which can make it hard to find. +;; +;; The same problem also exists in traditional windowing systems when +;; you use the keyboard to switch windows, e.g. with Alt-Tab. +;; +;; Because Emacs’ model is inverted, this suggests that the correct +;; behavior is also the inverse -- instead of using the mouse to +;; select a window to receive keyboard input, the keyboard should be +;; used to select the window to receive mouse input. +;; +;; `EXWM-MFF-MODE' is a global minor mode which does exactly this. +;; When the selected window in Emacs changes, the mouse pointer is +;; moved to its center, unless the pointer is already somewhere inside +;; the window’s bounds. While it's especially helpful for for EXWM +;; users, it works for any Emacs window in a graphical session. +;; +;; This package also offers the `EXWM-MFF-WARP-TO-SELECTED' command, +;; which allows you to summon the pointer with a hotkey. Unlike the +;; minor mode, summoning is unconditional, and will place the pointer in +;; the center of the window even if it already resides within its bounds +;; -- a handy feature if you’ve lost your pointer, even if you’re using +;; the minor mode. +;; +;; +;; Limitations +;; ~~~~~~~~~~~ +;; +;; None known at this time. + +;;; Code: + +(require 'subr-x) +(require 'cl-macs) + +(defcustom exwm-mff-ignore-if nil + "List of predicate functions for windows to ignore. + +Predicates accept one argument, WINDOW, and return non-NIL if +automatic pointer warping should be suppressed." + :type 'hook + :group 'exwm-mff) + +(defconst exwm-mff--debug-buffer " *exwm-mff-debug*" + "Name of the buffer exwm-mff will write debug messages into.") + +(defvar exwm-mff--debug 0 + "Whether (and how) to debug exwm-mff. +0 = don't debug. +1 = log messages to *exwm-mff-debug*. +2 = log messages to *exwm-mff-debug* and the echo area.") + +(defvar exwm-mff--last-window nil + "The last selected window.") + +(defun exwm-mff--guard () + "Raise an error unless this is a graphic session with mouse support." + (unless (and (display-graphic-p) (display-mouse-p)) + (error "EXWM-MFF-MODE doesn't work on non-graphic or non-mouse sessions"))) + +(defun exwm-mff--contains-pointer? (window) + "Return non-NIL when the mouse pointer is within FRAME and WINDOW." + (cl-destructuring-bind ((mouse-x . mouse-y) (left top right bottom)) + (list (mouse-absolute-pixel-position) + (window-absolute-pixel-edges window)) + (and (<= left mouse-x right) + (<= top mouse-y bottom)))) + +(defun exwm-mff--debug (string &rest objects) + "Log debug message STRING, using OBJECTS to format it." + (let ((debug-level (or exwm-mff--debug 0))) + (when (> debug-level 0) + (let ((str (apply #'format (concat "[%s] " string) + (cons (current-time-string) objects)))) + (when (>= debug-level 1) + (with-current-buffer (get-buffer-create exwm-mff--debug-buffer) + (goto-char (point-max)) + (insert (concat str "\n"))) + (when (>= debug-level 2) + (message str))))))) + +(defun exwm-mff-show-debug () + "Enable exwm-mff debugging, and show the buffer with debug logs." + (interactive) + (setq exwm-mff--debug 1) + (pop-to-buffer (get-buffer-create exwm-mff--debug-buffer))) + +(defun exwm-mff--window-center (window) + "Return a list of (x y) coordinates of the center of WINDOW in FRAME." + (cl-destructuring-bind (left top right bottom) (window-pixel-edges window) + (list (+ left (/ (- right left) 2)) + (+ top (/ (- bottom top) 2))))) + +(defun exwm-mff-warp-to (frame window) + "Place the pointer in the center of WINDOW in FRAME." + (apply #'set-mouse-pixel-position frame + (exwm-mff--window-center window))) + +;;;###autoload +(defun exwm-mff-warp-to-selected () + "Place the pointer in the center of the selected window." + (interactive) + (exwm-mff--guard) + (exwm-mff-warp-to (selected-frame) (selected-window))) + +(defun exwm-mff--explain (selected-window same-window? contains-pointer? mini? ignored?) + "Use SELECTED-WINDOW, SAME-WINDOW?, CONTAINS-POINTER?, MINI? +and IGNORED? to return an explanation of focusing behavior." + (cond + (same-window? "selected window hasn't changed") + (contains-pointer? "already contains pointer") + (mini? "is minibuffer") + (ignored? "one or more functions in `exwm-mff-ignore-if' matches") + (t (format "doesn't contain pointer (in %s)" selected-window)))) + +(defun exwm-mff-hook (sw &optional norecord) + "EXWM-MFF-MODE hook. + +This is after-advice placed on SELECT-WINDOW. It moves the +pointer to SW (the currently selected window), if NORECORD is +nil, and if it's not already in it." + (unless norecord + (if-let ((same-window? (eq sw exwm-mff--last-window))) + ;; The selected window is unchanged, we don't need to check + ;; anything else. + (exwm-mff--debug + "nop-> %s" (exwm-mff--explain sw same-window? nil nil nil)) + + (let* ((sf (window-frame sw)) + (contains-pointer? (exwm-mff--contains-pointer? sw)) + (mini? (minibufferp (window-buffer sw))) + (ignore? (run-hook-with-args-until-success 'exwm-mff-ignore-if sw))) + (if (or same-window? contains-pointer? mini? ignore?) + (exwm-mff--debug + "nop-> %s::%s (%s)" sf sw (exwm-mff--explain sw nil contains-pointer? mini? ignore?)) + (exwm-mff--debug + "warp-> %s::%s (%s)" sf sw (exwm-mff--explain sw nil contains-pointer? mini? ignore?)) + (exwm-mff-warp-to sf (setq exwm-mff--last-window sw))))))) + +(defgroup exwm-mff nil + "Mouse-Follows-Focus mode for EXWM." + :group 'exwm) + +;;;###autoload +(define-minor-mode exwm-mff-mode + "Mouse follows focus mode for EXWM." + :global t + :require 'exwm-mff + :group 'exwm-mff + (exwm-mff--guard) + (if exwm-mff-mode + (advice-add 'select-window :after #'exwm-mff-hook) + (advice-remove 'select-window #'exwm-mff-hook))) + +(provide 'exwm-mff) + +;;; exwm-mff.el ends here @@ -19,7 +19,6 @@ optimizeimg() { magick -strip -quality 85% $1 $2 } - killunattached() { tmux list-sessions -F '#{session_attached} #{session_id}' | \ awk '/^0/{print $2}' | \ @@ -43,10 +42,9 @@ notes() { grep -i "$1" --format='%f%~' ~/notes/ | xargs -I {} cat {} } - . /home/mccd/.nix-profile/etc/profile.d/nix.sh + . /home/mccd/.nix-profile/etc/profile.d/nix.sh -echo "BAT: $(cat /sys/class/power_supply/BAT0/capacity), $(cat /sys/class/power_supply/BAT0/status)" set -o vi PS1='\W \$ ' |