diff options
| author | jao <jao@gnu.org> | 2026-10-16 21:00:54 +0100 |
|---|---|---|
| committer | jao <jao@gnu.org> | 2026-10-16 21:04:03 +0100 |
| commit | f71a3084532ee7f959fc0b2cac384d0c2a14d8a1 (patch) | |
| tree | eee342032d4259f8c71afc3bf61bfb41d72cc405 | |
| parent | 2276be2575999fa174b910e371814bb712a11ea5 (diff) | |
| download | elibs-f71a3084532ee7f959fc0b2cac384d0c2a14d8a1.tar.gz elibs-f71a3084532ee7f959fc0b2cac384d0c2a14d8a1.tar.bz2 | |
exwm lib
| -rw-r--r-- | custom/jao-custom-exwm.el | 402 | ||||
| -rw-r--r-- | init.el | 2 | ||||
| -rw-r--r-- | lib/eos/jao-wayland.el | 182 | ||||
| -rw-r--r-- | lib/readme.org | 1 | ||||
| -rw-r--r-- | lib/wm/jao-exwm-zathura.el | 152 | ||||
| -rw-r--r-- | lib/wm/jao-exwm.el | 199 |
6 files changed, 384 insertions, 554 deletions
diff --git a/custom/jao-custom-exwm.el b/custom/jao-custom-exwm.el index 404b3cd..09a5180 100644 --- a/custom/jao-custom-exwm.el +++ b/custom/jao-custom-exwm.el @@ -1,12 +1,6 @@ ;; -*- lexical-binding: t; -*- -(require 'jao-pdf) - ;;; Load and basic config -(defvar jao-exwm--use-afio t) - -;; (jao-load-path "exwm") - (use-package exwm :ensure t :demand t @@ -18,252 +12,27 @@ exwm-floating-border-color (if (jao-colors-scheme-dark-p) "black" "grey90") ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=58245 : - x-no-window-manager t)) - -(use-package exwm-edit :ensure t) - -;;; Frame(s) as workspaces -(defun jao-exwm--new-frame-p () - (not (frame-parameter nil 'jao-frames-initialized))) - -(defun jao-exwm--mark-frame (force) - (prog1 (or force (jao-exwm--new-frame-p)) - (set-frame-parameter nil 'jao-frames-initialized t))) - -(defun jao-exwm--goto-main (&optional init) - (interactive "P") - (exwm-workspace-switch-create 1) - (when (jao-exwm--mark-frame init) (jao-trisect))) - -(defun jao-exwm--goto-mail (&optional init) - (interactive "P") - (exwm-workspace-switch-create 2) - (when (jao-exwm--mark-frame init) - (jao-afio-open-gnus))) - -(defun jao-exwm--goto-www (&optional init) - (interactive "P") - (exwm-workspace-switch-create 5) - (when (jao-exwm--mark-frame init) - (jao-afio-open-www) - (let ((scroll-bar-mode 'left)) - (toggle-scroll-bar 1) - (set-frame-parameter (window-frame) 'scroll-bar-width 12)) - (jao-toggle-inactive-mode-line))) - -(defun jao-exwm--goto-docs (&optional init) - (interactive "P") - (exwm-workspace-switch-create 4) - (when (jao-exwm--mark-frame init) - (jao-afio-open-doc))) - -(defun jao-exwm-open-doc (file) - (jao-exwm--goto-docs) - (jao-find-or-open file)) - -(defun jao-exwm-no-afio-setup () - (interactive) - (defalias 'jao-open-gnus-frame 'jao-exwm--goto-mail) - (defalias 'jao-goto-www-frame 'jao-exwm--goto-www) - (setq jao-open-doc-fun #'jao-exwm-open-doc) - (setq minibuffer-follows-selected-frame t) - (global-set-key "\C-cf" 'jao-exwm--goto-main) - (global-set-key "\C-cg" 'jao-exwm--goto-mail) - (global-set-key "\C-cw" 'jao-exwm--goto-www) - (global-set-key "\C-cz" 'jao-exwm--goto-docs)) - -(if jao-exwm--use-afio - (setq minibuffer-follows-selected-frame nil) - (jao-exwm-no-afio-setup)) - -;; tracking -(add-hook 'exwm-workspace-switch-hook 'tracking-remove-visible-buffers) - -;;; Buffer names -(defun jao-exwm--use-title-p () - (and exwm-title (not (string-blank-p exwm-title)))) - -(defun jao-exwm-rename-buffer/class () - (unless (jao-exwm--use-title-p) - (exwm-workspace-rename-buffer exwm-class-name))) - -(defun jao-exwm-rename-buffer/title () - (cond ((or (not exwm-instance-name) - (jao-exwm--use-title-p)) - (exwm-workspace-rename-buffer exwm-title)) - ((string= "Zathura" exwm-class-name) - (exwm-workspace-rename-buffer - (format "zathura: %s" (file-name-nondirectory exwm-title)))))) - -(defun jao-exwm--set-exwm-name () - (when (not jao-exwm--name) - (setq jao-exwm--name jao-exwm--current-name - jao-exwm--current-name nil))) - -(add-hook 'exwm-mode-hook 'jao-exwm--set-exwm-name) -(add-hook 'exwm-update-class-hook 'jao-exwm-rename-buffer/class) -(add-hook 'exwm-update-title-hook 'jao-minibuffer-refresh) -(add-hook 'exwm-update-title-hook 'jao-exwm-rename-buffer/title) - -;;; Float windows -(defvar jao-exwm-max-x (x-display-pixel-width)) -(defvar jao-exwm-max-y (x-display-pixel-height)) - -(defun jao-exwm--float-to (x y &optional w h) - (let* ((w (or w (frame-pixel-width))) - (h (or h (frame-pixel-height))) - (x (if (< x 0) (- jao-exwm-max-x (- x) w) x)) - (y (if (< y 0) (- jao-exwm-max-y (- y) h) y)) - (p (or (frame-parameter nil 'jao-position) (frame-position)))) - (exwm-floating-move (- x (car p)) (- y (cdr p))) - (exwm-layout-enlarge-window-horizontally (- w (frame-pixel-width))) - (exwm-layout-enlarge-window (- h (frame-pixel-height))) - (set-frame-parameter nil 'jao-position (cons x y)))) - -(defun jao-exwm--center-float (&optional w h) - (interactive) - (let* ((mx jao-exwm-max-x) - (my jao-exwm-max-y) - (w (or w (frame-pixel-width))) - (h (or h (/ (* w my) mx)))) - (jao-exwm--float-to (/ (- mx w) 2) (/ (- my h) 2) w h))) - -(defun jao-exwm--setup-float () - (set-frame-parameter nil 'jao-position nil) - (cond ((member exwm-class-name '("firefox" "Firefox" "Sofice")) - (jao-exwm--center-float 900 600)) - ((member exwm-class-name '("mpv" "vlc")) - (jao-exwm--center-float 1200)))) - -(defvar jao-exwm-floating-classes '("mpv" "vlc")) -(setq jao-exwm-floating-classes nil) - -(defun jao-exwm--maybe-float () - (when (member exwm-class-name jao-exwm-floating-classes) - (when (not exwm--floating-frame) - (exwm-floating-toggle-floating)))) - -(add-hook 'exwm-floating-setup-hook #'jao-exwm--setup-float) -(add-hook 'exwm-manage-finish-hook #'jao-exwm--maybe-float) - -;; Minibuffer and system tray -(setq jao-minibuffer-frame-width 271) -(add-hook 'exwm-workspace-switch-hook #'jao-minibuffer-refresh) - -(require 'exwm-systemtray) -(exwm-systemtray-mode 1) - -(defun jao-exwm--watch-tray (sym newval op where) - (setq jao-minibuffer-right-margin (/ newval (string-pixel-width "a"))) - (jao-minibuffer-refresh)) - -(add-variable-watcher 'exwm-systemtray-width #'jao-exwm--watch-tray) - -;; Switch to buffer / app -(defvar-local jao-exwm--name nil) -(defvar jao-exwm--current-name nil) - -(defun jao-exwm--check-name (name) - (or (string= jao-exwm--name name) - (string= (buffer-name) name) - (string= exwm-class-name name) - (string= exwm-title name))) - -(defun jao-exwm-find-class-buffer (cln) - (if (jao-exwm--check-name cln) - (current-buffer) - (let* ((cur-buff (current-buffer)) - (bfs (seq-filter (lambda (b) - (and (not (eq b cur-buff)) - (with-current-buffer b - (jao-exwm--check-name cln)))) - (buffer-list)))) - (when (car bfs) (car (reverse bfs)))))) - -(defun jao-exwm-switch-to-class/title (cln) - (interactive) - (when cln - (if (jao-exwm--check-name cln) - (current-buffer) - (when-let* ((b (jao-exwm-find-class-buffer cln))) - (pop-to-buffer b))))) - -(defun jao-exwm-switch-to-next-class () - (interactive) - (jao-exwm-switch-to-class/title exwm-class-name)) - -(defun jao-exwm-switch-to-next-x () - (interactive) - (let ((bfs (seq-filter (lambda (b) - (with-current-buffer b - (derived-mode-p 'exwm-mode))) - (buffer-list (window-frame))))) - (when (car bfs) (switch-to-buffer (car (reverse bfs)))))) - -;;; App runner helpers -(defun jao-exwm-run (command) - (interactive - (list (read-shell-command "$ " - (if current-prefix-arg - (cons (concat " " (buffer-file-name)) 0) - "")))) - (setq jao-exwm--current-name nil) - (start-process-shell-command command nil command)) + x-no-window-manager t) + :config + (use-package jao-exwm + :demand t) -(defmacro jao-exwm-runner (&rest args) - `(lambda () (interactive) (start-process "" nil ,@args))) + (use-package exwm-edit :ensure t)) -(defun jao-exwm-workspace (n) - (if jao-exwm--use-afio - (jao-afio-goto-nth n) - (exwm-workspace-switch-create n))) - -(defmacro jao-def-exwm-runner (name ws class &rest args) - `(defun ,name (&rest other-args) - (interactive) - ,@(when ws `((jao-exwm-workspace ,ws))) - (if (jao-exwm-switch-to-class/title ,class) - ,(cond ((equal ws -1) '(delete-other-windows)) - ((stringp (car args)) (cdr args)) - (t args)) - (setq jao-exwm--current-name ,class) - ,(if (stringp (car args)) - `(start-process-shell-command ,(car args) - "* exwm - console *" - (string-join (append (list ,@args) - other-args) - " ")) - args)))) - -(defmacro jao-def-exwm-toggler (name ws class &rest args) - (let ((toggler (intern (format "%s*" name))) - (arg (gensym))) - `(progn (jao-def-exwm-runner ,name ,ws ,class ,@args) - (defun ,toggler (,arg) - (interactive "P") - (if (and (not ,arg) (equal exwm-class-name ,class)) - (jao-afio-toggle) - (,name)))))) - -(defun jao-exwm--send-str (str) - (dolist (k (string-to-list (kbd str))) - (exwm-input--fake-key k))) ;;; Runners -(jao-def-exwm-runner jao-exwm-vlc 4 "VLC" "vlc") - -(jao-def-exwm-runner jao-exwm-slack 0 "Slack" "slack") -(jao-def-exwm-runner jao-exwm-signal 0 "Signal" "signal-desktop") - -(jao-def-exwm-runner jao-exwm-proton-bridge 0 "*proton-bridge*" "protonmail-bridge") +;; (jao-def-exwm-runner jao-exwm-vlc 4 "VLC" "vlc") +;; (jao-def-exwm-runner jao-exwm-slack 0 "Slack" "slack") +;; (jao-def-exwm-runner jao-exwm-signal 0 "Signal" "signal-desktop") +;; (jao-def-exwm-runner jao-exwm-proton-bridge 0 "*proton-bridge*" "protonmail-bridge") ;; (jao-def-exwm-runner jao-exwm-htop 0 "htop-xterm" ;; "xterm" "-title" "htop-xterm" "-e" "htop") (jao-def-exwm-runner jao-exwm-htop 0 "htop" jao-term-htop) -;; (jao-def-exwm-runner jao-exwm-aptitude 0 "aptitude-xterm" -;; "xterm" "-title" "aptitude-xterm" "-e" "aptitude") -(jao-def-exwm-runner jao-exwm-aptitude 0 "aptitude" jao-term-aptitude) +(jao-def-exwm-runner jao-exwm-aptitude 0 "aptitude-xterm" + "xterm" "-title" "aptitude-xterm" "-e" "aptitude") +;; (jao-def-exwm-runner jao-exwm-aptitude 0 "aptitude" jao-term-aptitude) (jao-def-exwm-runner jao-exwm-blueman 0 "Blueman-manager" "blueman-manager") (jao-def-exwm-runner jao-exwm-ncmpcpp 0 "ncmpcpp" "xterm" "-e" "ncmpcpp" "-p" "6669") @@ -279,10 +48,7 @@ (jao-def-exwm-runner jao-exwm-open-with-mupdf nil nil "mupdf" (buffer-file-name)) (jao-def-exwm-runner jao-exwm-xterm 0 nil "xterm") -;; (jao-def-exwm-toggler jao-exwm-tidal -1 "tidal-hifi" "tidal-hifi") -;; (jao-def-exwm-toggler jao-exwm-spt -1 "spt" "kitty" "-e" "spt") -;; (defalias 'jao-streaming-list #'jao-exwm-spt*) - +;;; Screenshot (defun jao-exwm-import-screen (&optional area) (interactive "P") (when (not (file-directory-p "/tmp/screenshot")) @@ -292,127 +58,6 @@ "/tmp/screenshot/$(date +'%g%m%d-%H%M%S').png"))) (start-process-shell-command "import" "* exwm - console *" c))) -;;; Zathura support -(defun jao-zathura--buffer-p (b) - (string= "Zathura" (or (buffer-local-value 'exwm-class-name b) ""))) - -(defun jao-zathura--buffers () - (seq-filter #'jao-zathura--buffer-p (buffer-list))) - -(defun jao-zathura--file-info (b) - (with-current-buffer b - (jao-pdf-zathura-file-info (or exwm-title "")))) - -(defun jao-zathura-goto-page (page-no) - (jao-exwm--send-str (format "%sg" page-no))) - -(defun jao-zathura-open-doc (&optional file-name page-no height) - (interactive) - (let* ((file-name (expand-file-name (or file-name (buffer-file-name)))) - (buffer (seq-find `(lambda (b) - (string= ,file-name - (car (jao-zathura--file-info b)))) - (jao-zathura--buffers))) - (page-no (or page-no (jao-doc-view-current-page)))) - (if jao-exwm--use-afio (jao-afio-goto-docs) (jao-exwm--goto-docs)) - (if (not buffer) - (jao-exwm-run (if page-no - (format "zathura -P %s '%s'" page-no file-name) - (format "zathura '%s'" file-name))) - (pop-to-buffer buffer) - (when page-no (jao-zathura-goto-page page-no))) - (current-buffer))) - -(defun jao-exwm--zathura-setup () - (when (and (string= exwm-class-name "Zathura") - (not jao-pdf--outline)) - (let ((info (jao-zathura--file-info (current-buffer)))) - (jao-doc-session-mark (car info)) - (jao-doc-session-save) - (doc-view-imenu-index (car info) #'jao-zathura-goto-page)))) - -(add-hook 'exwm-update-title-hook #'jao-exwm--zathura-setup t) - -(defun jao-exwm-pdf-zathura-close-all () - (interactive) - (dolist (b (jao-zathura--buffers)) - (ignore-errors - (switch-to-buffer b) - (jao-exwm--send-str "q"))) - t) - -(defun jao-exwm-zathura-goto-org (&optional arg) - (interactive "P") - (when-let* ((info (jao-zathura--file-info (current-buffer))) - (file (jao-org-find-for-pdf (car info)))) - (let ((newp (not (file-exists-p file)))) - (when (or arg newp) (org-store-link nil t)) - (find-file-other-window file) - (when newp - (jao-org-insert-doc-skeleton) - (org-insert-link))))) - -(defun jao-exwm-zathura-goto-org* () - (interactive) - (jao-exwm-zathura-goto-org t)) - -(defun jao-exwm-org-store-zathura-link () - (when-let* ((info (jao-zathura--file-info (current-buffer)))) - (let* ((file-name (car info)) - (page (cadr info)) - (desc (jao-pdf-section-title page file-name))) - (jao-org-links-store-pdf-link file-name page desc)))) - -(defun jao-exwm-pdf-enable-zathura () - (interactive) - (add-hook 'kill-emacs-query-functions #'jao-exwm-pdf-zathura-close-all t) - (setq jao-pdf-open-in-emacs nil) - (setq jao-org-open-pdf-fun #'jao-zathura-open-doc) - (setq jao-org-links-pdf-store-fun #'jao-exwm-org-store-zathura-link) - (setq jao-open-doc-fun #'jao-zathura-open-doc)) - -(defun jao-exwm-pdf-disable-zathura () - (interactive) - (remove-hook 'kill-emacs-query-functions #'jao-exwm-pdf-zathura-close-all) - (setq jao-pdf-open-in-emacs t) - (setq jao-org-open-pdf-fun #'jao-find-or-open) - (setq jao-org-links-pdf-store-fun nil) - (setq jao-open-doc-fun #'jao-find-or-open)) - -(defun jao-exwm-org-to-pdf-file () - (expand-file-name (concat "doc/" (file-name-base buffer-file-name) ".pdf") - (file-name-directory jao-org-notes-dir))) - -(defun jao-exwm-zathura-goto-pdf () - (interactive) - (if jao-pdf-open-in-emacs - (jao-org-goto-pdf) - (when-let* ((pdf (jao-exwm-org-to-pdf-file))) - (jao-zathura-open-doc pdf)))) - -(with-eval-after-load "org" - (define-key org-mode-map (kbd "C-c o") #'jao-exwm-zathura-goto-pdf)) - -(when (not jao-pdf-open-in-emacs) - (jao-exwm-pdf-enable-zathura)) - -(defun jao-exwm-select-pdf () - (interactive) - (let ((b (read-buffer "Document: " nil t - (lambda (b) - (let ((b (cdr b))) - (or (jao-zathura--buffer-p b) - (member (buffer-local-value 'major-mode b) - '(pdf-view-mode doc-view-mode)))))))) - (jao-afio-goto-docs) - (pop-to-buffer b))) - - -(jao-transient-major-mode+ doc-view - ["External viewers" - ("z" "open with zathura" jao-zathura-open-doc) - ("m" "open with mupdf" jao-exwm-open-with-mupdf)]) - ;;; Firefox support (jao-def-exwm-toggler jao-exwm-firefox -1 "firefox" "firefox") @@ -424,14 +69,30 @@ (defun jao-exwm-kill-firefox-url () (interactive) - (when-let* ((b (jao-exwm-find-class-buffer "Firefox"))) + (when-let* ((b (jao-exwm-find-class-buffer "firefox"))) (let ((cb (current-buffer))) (switch-to-buffer b) - (jao-exwm--send-str "yy") + (exwm-input--fake-key ?y) + (exwm-input--fake-key ?y) (prog1 (current-kill 1) (switch-to-buffer cb))))) +(defun jao-exwm-firefox-search (query) + (interactive "sQuery: ") + (jao-exwm-firefox) + (sit-for 0.5) + (exwm-input--fake-key ?s) + (dolist (k (string-to-list query)) + (exwm-input--fake-key k)) + (sit-for 0.5) + (exwm-input--fake-key ?\r)) + ;;; Transients +(jao-transient-major-mode+ doc-view + ["External viewers" + ("z" "open with zathura" jao-zathura-open-doc) + ("m" "open with mupdf" jao-exwm-open-with-mupdf)]) + (defun jao-exwm--floating-p () exwm--floating-frame) (defun jao-exwm--m0-5 () (interactive nil exwm-mode) (exwm-floating-move 0 -5)) (defun jao-exwm--m05 () (interactive nil exwm-mode) (exwm-floating-move 0 5)) @@ -526,7 +187,6 @@ ([?\s-\`] . jao-exwm-switch-to-next-x) ([s-tab] . jao-exwm-switch-to-next-class) ([print] . jao-exwm-import-screen) - ([f5] . jao-weather) ([f6] . jao-toggle-audio-applet) ([f8] . jao-toggle-nm-applet) ([f9] . jao-bright-show))) @@ -1174,7 +1174,7 @@ (defun jao-current--frame-id () (propertize (cond ((and (fboundp 'jao-exwm-enabled) (jao-exwm-enabled-p) - (not (bound-and-true-p jao-exwm--use-afio)) + (not (bound-and-true-p jao-exwm-use-afio)) (boundp 'exwm-workspace-current-index)) (format "F%s" exwm-workspace-current-index)) (t (format "%s" (or (jao-afio-frame-name) "")))) diff --git a/lib/eos/jao-wayland.el b/lib/eos/jao-wayland.el deleted file mode 100644 index e743eb0..0000000 --- a/lib/eos/jao-wayland.el +++ /dev/null @@ -1,182 +0,0 @@ -;;; jao-wayland.el --- interacting with wayland compositors -*- lexical-binding: t; -*- - -;; Copyright (C) 2022, 2023 jao - -;; Author: jao <mail@jao.io> -;; Keywords: convenience - -;; 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 <https://www.gnu.org/licenses/>. - -(require 'browse-url) -(require 'jao-shell) -(require 'jao-pdf) -(require 'jao-tracking) - -;;; wayland -(defvar jao-wayland-enabled - (string= "wayland" (or (getenv "XDG_SESSION_TYPE") ""))) - -(defsubst jao-wayland-type (&rest args) - (apply #'jao-shell-exec* t "wtype" args)) - -;;; river -(defvar jao-river-enabled (jao-shell-running-p "river")) -(defun jao-river-enabled-p () jao-river-enabled) - -(defsubst jao-river-to-ws (n) - (jao-wayland-type "-M" "win" (format "%s" n))) - -(defsubst jao-river-window-list () - (alist-get 'toplevels - (jao-shell-output "lswt -j" - (lambda () - (let ((json-false nil)) (json-read)))))) - -(defun jao-river-focused () - (seq-some (lambda (w) (and (alist-get 'activated w) w)) - (jao-river-window-list))) - -(defsubst jao-river-get-focused-title () - (alist-get 'title (jao-river-focused))) - -(defsubst jao-river-get-focused-app-id () - (alist-get 'app-id (jao-river-focused))) - -(defun jao-river-focus-window (title &optional rx) - (let* ((ws (jao-river-window-list)) - (fltr (if rx #'string-match-p #'string=)) - (w (seq-find (lambda (w) - (or (funcall fltr title (alist-get 'app_id w "")) - (funcall fltr title (alist-get 'title w "")))) - ws))) - (or (alist-get 'activated w) - (seq-some (lambda (_ignored) - (jao-shell-exec "riverctl focus-view next" t) - (or (funcall fltr title (jao-river-get-focused-app-id)) - (funcall fltr title (jao-river-get-focused-title)))) - (and w ws))))) - -(defun jao-river-zathura-to-org () - (let ((title (jao-river-get-focused-title))) - (jao-river-to-ws 1) - (jao-org-open-from-zathura title t))) - -(defun jao-river-zathura-kill-link () - (when-let* ((title (jao-river-get-focused-title)) - (lnk (jao-pdf-zathura-org-link title))) - (jao-river-to-ws 1) - (kill-new lnk) - (message "Link to %s killed" title))) - -(defun jao-river-find-zathura-window (file) - (let ((frx (regexp-quote (file-name-nondirectory file)))) - (seq-some (lambda (w) - (and (string-suffix-p ".zathura" (alist-get 'app_id w "")) - (string-match-p frx (alist-get 'title w "")) - w)) - (jao-river-window-list)))) - -(defun jao-river-open-with-zathura (file page) - (let ((wd (jao-river-find-zathura-window file))) - (jao-river-to-ws 3) - (or (and wd (jao-river-focus-window (alist-get 'title wd))) - (jao-shell-exec* "riverctl" "spawn" (jao-pdf-zathura-open-cmd file page))) - (when page (sit-for 0.2) (jao-wayland-type (format "%dg" page))))) - -(defun jao-river-set-wallpaper (f) - (jao-shell-kill-p "swaybg") - (jao-shell-exec* "riverctl" "spawn" (concat "swaybg -m fill -i " f))) - -(defun jao-river-restart-i3bar () - (interactive) - (jao-shell-kill-p "i3bar-river") - (jao-shell-exec "riverctl spawn i3bar-river") - (sit-for 0.2) - (jao-tracking-set-log "")) - -(defun jao-river-toggle-emacs () - (let ((erx "^p?emacs\\(client\\)?\\|\\(.* - emacs\\)")) - (if (or (string-match-p erx (jao-river-get-focused-title)) - (string-match-p erx (jao-river-get-focused-app-id))) - (jao-shell-exec "riverctl focus-previous-tags") - (jao-river-to-ws 1) - (unless (jao-river-focus-window erx t) - (jao-shell-exec* "riverctl" "spawn" "efoot"))))) - -(defun jao-river-toggle-firefox () - (if (string-match-p "Firefox" (or (jao-river-get-focused-app-id) "")) - (jao-river-to-ws 1) - (jao-river-to-ws 2) - (unless (jao-river-focus-window "Firefox") - (jao-shell-exec* "riverctl" "spawn" "firefox")))) - -;;; sway -(defun jao-sway-msg (msg) - (shell-command (format "swaymsg '%s' >/dev/null" msg))) - -(defmacro jao-def-swaymsg (name msg) - `(defun ,(intern (format "jao-sway-%s" name)) () - (interactive) - (jao-sway-msg ,msg))) - -(jao-def-swaymsg firefox "[app_id=Firefox] focus") -(jao-def-swaymsg pemacs "[app_id=pemacs] focus") - -(defvar jao-sway-enabled (jao-shell-running-p "sway")) - -(defconst jao-sway-get-active-title - "swaymsg -t get_tree | jq '.. | select(.type?) | select(.focused==true).name'") - -(defconst jao-sway-get-active-app - "swaymsg -t get_tree | jq '.. | select(.type?) | select(.focused==true).app_id'") - -(defun jao-sway-get-active-title () - (let ((tl (jao-shell-string jao-sway-get-active-title))) - (and (string-match "\"\\(.+\\)\"" tl) (match-string 1 tl)))) - -(defun jao-sway-get-active-app () - (let ((tl (jao-shell-string jao-sway-get-active-app))) - (and (string-match "\"\\(.+\\)\"" tl) (match-string 1 tl)))) - -(defun jao-sway-zathura-org () - (jao-org-open-from-zathura (jao-sway-get-active-title) t)) - -(defun jao-sway-open-with-zathura (file page) - (let* ((n (file-name-nondirectory file)) - (m (format "[title=\"%s\" app_id=\".*zathura\"] focus" n))) - (jao-sway-msg "workspace number 3") - (unless (= 0 (jao-sway-msg m)) - (jao-shell-exec (jao-pdf-zathura-open-cmd file page))) - (when page (sit-for 0.2) (jao-wayland-type (format "%dg" page))))) - -(defun jao-sway-set-wallpaper (f) - (jao-sway-msg (format "output * bg %s fill" f))) - -(defun jao-sway-run-or-focus (cmd &optional ws) - (if (jao-shell-running-p "firefox") - (jao-sway-msg (format "[app_id=%s] focus" cmd)) - (jao-sway-msg (format "workspace %s" (or ws 2))) - (start-process-shell-command cmd nil cmd))) - -(defun jao-sway-run-or-focus-firefox () - (interactive) - (jao-sway-run-or-focus "firefox")) - -(defun jao-sway-toggle-emacs () - (if (string-match-p "p?emacs" (jao-sway-get-active-app)) - (jao-sway-firefox) - (jao-sway-pemacs))) - -(provide 'jao-wayland) -;;; jao-wayland.el ends here diff --git a/lib/readme.org b/lib/readme.org index 60b1942..35faccb 100644 --- a/lib/readme.org +++ b/lib/readme.org @@ -5,4 +5,5 @@ - [[./media][media]] utilities for music players and the like - [[./prog][prog]] utilities for compilation and programming modes - [[./net][net]] utilities for networking (w3m, weather &c.) + - [[./wm][wm]] utilities for interacting with window managers - [[./skels][skels]] a collection of emacs skeletons diff --git a/lib/wm/jao-exwm-zathura.el b/lib/wm/jao-exwm-zathura.el new file mode 100644 index 0000000..9da0a25 --- /dev/null +++ b/lib/wm/jao-exwm-zathura.el @@ -0,0 +1,152 @@ +;;; jao-exwm-zathura.el --- running zathura as doc manager -*- lexical-binding: t; -*- + +;; Copyright (C) 2026 jao + +;; Author: jao <mail@jao.io> +;; Keywords: docs + +;; 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 <https://www.gnu.org/licenses/>. + +(require 'jao-exwm) +(require 'jao-pdf) +(require 'jao-doc-view) +(require 'jao-afio) +(require 'jao-org-notes) + +;;; Zathura support +(defun jao-zathura--buffer-p (b) + (string= "Zathura" (or (buffer-local-value 'exwm-class-name b) ""))) + +(defun jao-zathura--buffers () + (seq-filter #'jao-zathura--buffer-p (buffer-list))) + +(defun jao-zathura--file-info (b) + (with-current-buffer b + (jao-pdf-zathura-file-info (or exwm-title "")))) + +(defun jao-zathura-goto-page (page-no) + (jao-exwm-send-str (format "%sg" page-no))) + +;;;###autoload +(defun jao-zathura-open-doc (&optional file-name page-no _height) + (interactive) + (let* ((file-name (expand-file-name (or file-name (buffer-file-name)))) + (buffer (seq-find `(lambda (b) + (string= ,file-name + (car (jao-zathura--file-info b)))) + (jao-zathura--buffers))) + (page-no (or page-no (jao-doc-view-current-page)))) + (when jao-exwm-use-afio (jao-afio-goto-docs)) + (if (not buffer) + (jao-exwm-run (if page-no + (format "zathura -P %s '%s'" page-no file-name) + (format "zathura '%s'" file-name))) + (pop-to-buffer buffer) + (when page-no (jao-zathura-goto-page page-no))) + (current-buffer))) + +(defun jao-exwm--zathura-setup () + (when (and (string= exwm-class-name "Zathura") + (not jao-pdf--outline)) + (let ((info (jao-zathura--file-info (current-buffer)))) + (jao-doc-session-mark (car info)) + (jao-doc-session-save) + (doc-view-imenu-index (car info) #'jao-zathura-goto-page)))) + +(add-hook 'exwm-update-title-hook #'jao-exwm--zathura-setup t) + +;;;###autoload +(defun jao-exwm-pdf-zathura-close-all () + (interactive) + (dolist (b (jao-zathura--buffers)) + (ignore-errors + (switch-to-buffer b) + (jao-exwm-send-str "q"))) + t) + +;;;###autoload +(defun jao-exwm-zathura-goto-org (&optional arg) + (interactive "P") + (when-let* ((info (jao-zathura--file-info (current-buffer))) + (file (jao-org-find-for-pdf (car info)))) + (let ((newp (not (file-exists-p file)))) + (when (or arg newp) (org-store-link nil t)) + (find-file-other-window file) + (when newp + (jao-org-insert-doc-skeleton) + (org-insert-link))))) + +;;;###autoload +(defun jao-exwm-zathura-goto-org* () + (interactive) + (jao-exwm-zathura-goto-org t)) + +;;;###autoload +(defun jao-exwm-org-store-zathura-link () + (when-let* ((info (jao-zathura--file-info (current-buffer)))) + (let* ((file-name (car info)) + (page (cadr info)) + (desc (jao-pdf-section-title page file-name))) + (jao-org-links-store-pdf-link file-name page desc)))) + +;;;###autoload +(defun jao-exwm-pdf-enable-zathura () + (interactive) + (add-hook 'kill-emacs-query-functions #'jao-exwm-pdf-zathura-close-all t) + (setq jao-pdf-open-in-emacs nil) + (setq jao-org-open-pdf-fun #'jao-zathura-open-doc) + (setq jao-org-links-pdf-store-fun #'jao-exwm-org-store-zathura-link) + (setq jao-open-doc-fun #'jao-zathura-open-doc)) + +;;;###autoload +(defun jao-exwm-pdf-disable-zathura () + (interactive) + (remove-hook 'kill-emacs-query-functions #'jao-exwm-pdf-zathura-close-all) + (setq jao-pdf-open-in-emacs t) + (setq jao-org-open-pdf-fun #'jao-find-or-open) + (setq jao-org-links-pdf-store-fun nil) + (setq jao-open-doc-fun #'jao-find-or-open)) + +;;;###autoload +(defun jao-exwm-org-to-pdf-file () + (expand-file-name (concat "doc/" (file-name-base buffer-file-name) ".pdf") + (file-name-directory jao-org-notes-dir))) + +;;;###autoload +(defun jao-exwm-zathura-goto-pdf () + (interactive) + (if jao-pdf-open-in-emacs + (jao-org-goto-pdf) + (when-let* ((pdf (jao-exwm-org-to-pdf-file))) + (jao-zathura-open-doc pdf)))) + +(with-eval-after-load "org" + (define-key org-mode-map (kbd "C-c o") #'jao-exwm-zathura-goto-pdf)) + +(when (not jao-pdf-open-in-emacs) + (jao-exwm-pdf-enable-zathura)) + +(defun jao-exwm-select-pdf () + (interactive) + (let ((b (read-buffer "Document: " nil t + (lambda (b) + (let ((b (cdr b))) + (or (jao-zathura--buffer-p b) + (member (buffer-local-value 'major-mode b) + '(pdf-view-mode doc-view-mode)))))))) + (jao-afio-goto-docs) + (pop-to-buffer b))) + +(provide 'jao-exwm-zathura) +;;; jao-exwm-zathura.el ends here diff --git a/lib/wm/jao-exwm.el b/lib/wm/jao-exwm.el new file mode 100644 index 0000000..52a2e34 --- /dev/null +++ b/lib/wm/jao-exwm.el @@ -0,0 +1,199 @@ +;;; jao-exwm.el --- exwm utilities -*- lexical-binding: t; -*- + +;; Copyright (C) 2026 jao + +;; Author: jao <mail@jao.io> + +;; 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 <https://www.gnu.org/licenses/>. + +(require 'jao-minibuffer) + +;;; Helpers +(defvar jao-exwm-use-afio t) + +(defun jao-exwm-send-str (str) + (dolist (k (string-to-list str)) + (exwm-input--fake-key k))) + +;;; Minibuffer and system tray +(setq jao-minibuffer-frame-width 271) +(add-hook 'exwm-workspace-switch-hook #'jao-minibuffer-refresh) + +(require 'exwm-systemtray) +(exwm-systemtray-mode 1) + +(defun jao-exwm--watch-tray (sym newval op where) + (setq jao-minibuffer-right-margin (/ newval (string-pixel-width "a"))) + (jao-minibuffer-refresh)) + +(add-variable-watcher 'exwm-systemtray-width #'jao-exwm--watch-tray) + +;;; Buffers +(defvar-local jao-exwm--name nil) +(defvar jao-exwm--current-name nil) + +(defun jao-exwm--check-name (name) + (or (string= jao-exwm--name name) + (string= (buffer-name) name) + (string= exwm-class-name name) + (string= exwm-title name))) + +(defun jao-exwm-find-class-buffer (cln) + (if (jao-exwm--check-name cln) + (current-buffer) + (let* ((cur-buff (current-buffer)) + (bfs (seq-filter (lambda (b) + (and (not (eq b cur-buff)) + (with-current-buffer b + (jao-exwm--check-name cln)))) + (buffer-list)))) + (when (car bfs) (car (reverse bfs)))))) + +(defun jao-exwm-switch-to-class/title (cln) + (interactive) + (when cln + (if (jao-exwm--check-name cln) + (current-buffer) + (when-let* ((b (jao-exwm-find-class-buffer cln))) + (pop-to-buffer b))))) + +(defun jao-exwm-switch-to-next-class () + (interactive) + (jao-exwm-switch-to-class/title exwm-class-name)) + +(defun jao-exwm-switch-to-next-x () + (interactive) + (let ((bfs (seq-filter (lambda (b) + (with-current-buffer b + (derived-mode-p 'exwm-mode))) + (buffer-list (window-frame))))) + (when (car bfs) (switch-to-buffer (car (reverse bfs)))))) + +;;; Buffer names +(defun jao-exwm--use-title-p () + (and exwm-title (not (string-blank-p exwm-title)))) + +(defun jao-exwm-rename-buffer/class () + (unless (jao-exwm--use-title-p) + (exwm-workspace-rename-buffer exwm-class-name))) + +(defun jao-exwm-rename-buffer/title () + (cond ((or (not exwm-instance-name) + (jao-exwm--use-title-p)) + (exwm-workspace-rename-buffer exwm-title)) + ((string= "Zathura" exwm-class-name) + (exwm-workspace-rename-buffer + (format "zathura: %s" (file-name-nondirectory exwm-title)))))) + +(defun jao-exwm--set-exwm-name () + (when (not jao-exwm--name) + (setq jao-exwm--name jao-exwm--current-name + jao-exwm--current-name nil))) + +(add-hook 'exwm-mode-hook 'jao-exwm--set-exwm-name) +(add-hook 'exwm-update-class-hook 'jao-exwm-rename-buffer/class) +(add-hook 'exwm-update-title-hook 'jao-minibuffer-refresh) +(add-hook 'exwm-update-title-hook 'jao-exwm-rename-buffer/title) + +;;; Float windows +(defvar jao-exwm-max-x (x-display-pixel-width)) +(defvar jao-exwm-max-y (x-display-pixel-height)) + +(defun jao-exwm--float-to (x y &optional w h) + (let* ((w (or w (frame-pixel-width))) + (h (or h (frame-pixel-height))) + (x (if (< x 0) (- jao-exwm-max-x (- x) w) x)) + (y (if (< y 0) (- jao-exwm-max-y (- y) h) y)) + (p (or (frame-parameter nil 'jao-position) (frame-position)))) + (exwm-floating-move (- x (car p)) (- y (cdr p))) + (exwm-layout-enlarge-window-horizontally (- w (frame-pixel-width))) + (exwm-layout-enlarge-window (- h (frame-pixel-height))) + (set-frame-parameter nil 'jao-position (cons x y)))) + +(defun jao-exwm--center-float (&optional w h) + (interactive) + (let* ((mx jao-exwm-max-x) + (my jao-exwm-max-y) + (w (or w (frame-pixel-width))) + (h (or h (/ (* w my) mx)))) + (jao-exwm--float-to (/ (- mx w) 2) (/ (- my h) 2) w h))) + +(defun jao-exwm--setup-float () + (set-frame-parameter nil 'jao-position nil) + (cond ((member exwm-class-name '("firefox" "Firefox" "Sofice")) + (jao-exwm--center-float 900 600)) + ((member exwm-class-name '("mpv" "vlc")) + (jao-exwm--center-float 1200)))) + +(defvar jao-exwm-floating-classes '("mpv" "vlc")) +(setq jao-exwm-floating-classes nil) + +(defun jao-exwm--maybe-float () + (when (member exwm-class-name jao-exwm-floating-classes) + (when (not exwm--floating-frame) + (exwm-floating-toggle-floating)))) + +(add-hook 'exwm-floating-setup-hook #'jao-exwm--setup-float) +(add-hook 'exwm-manage-finish-hook #'jao-exwm--maybe-float) + +;;; App runners +;;; App runner helpers +(defun jao-exwm-run (command) + (interactive + (list (read-shell-command "$ " + (if current-prefix-arg + (cons (concat " " (buffer-file-name)) 0) + "")))) + (setq jao-exwm--current-name nil) + (start-process-shell-command command nil command)) + +(defmacro jao-exwm-runner (&rest args) + `(lambda () (interactive) (start-process "" nil ,@args))) + +(defun jao-exwm-workspace (n) + (if jao-exwm-use-afio + (jao-afio-goto-nth n) + (exwm-workspace-switch-create n))) + +(defmacro jao-def-exwm-runner (name ws class &rest args) + `(defun ,name (&rest other-args) + (interactive) + ,@(when ws `((jao-exwm-workspace ,ws))) + (if (jao-exwm-switch-to-class/title ,class) + ,(cond ((equal ws -1) '(delete-other-windows)) + ((stringp (car args)) (cdr args)) + (t args)) + (setq jao-exwm--current-name ,class) + ,(if (stringp (car args)) + `(start-process-shell-command ,(car args) + "* exwm - console *" + (string-join (append (list ,@args) + other-args) + " ")) + args)))) + +(defmacro jao-def-exwm-toggler (name ws class &rest args) + (let ((toggler (intern (format "%s*" name))) + (arg (gensym))) + `(progn (jao-def-exwm-runner ,name ,ws ,class ,@args) + (defun ,toggler (,arg) + (interactive "P") + (if (and (not ,arg) (equal exwm-class-name ,class)) + (jao-afio-toggle) + (,name)))))) + + + +(provide 'jao-exwm) +;;; jao-exwm.el ends here |
