(require 'cl-lib) (require 'counsel) (require 'posframe) (require 'exwm-panel) ;; (("yelp.desktop" . "/usr/share/applications/yelp.desktop") ;; ("xsane.desktop" . "/usr/share/applications/xsane.desktop") ;; ("xpad.desktop" . "/usr/share/applications/xpad.desktop")) (defvar exwm-apps (progn (message "Collecting all desktop fiels. This will take a while. Please wait.") (counsel-linux-apps-list-desktop-files))) (defvar exwm-app-icons (progn (message "Collecting all app icons. This will take a while. Please wait.") (setq exwm-app-icons (cl-loop for dir in (list "/usr/share/icons/") when (file-exists-p dir) append (directory-files-recursively dir (rx-to-string `(or ,@(mapcar (lambda (extn) `(and "." ,extn eos)) '("png" "xpm" "svg" "pbm"))))))))) (defun exwm-find-icon-file (icon-name) (cl-loop for icon-file in exwm-app-icons when (string= icon-name (file-name-sans-extension (file-name-nondirectory icon-file))) return (let ((icon-size (car (image-size (create-image icon-file) t)))) ;; (message "%s -> %s " icon-file icon-size) (create-image icon-file nil nil ;; :scale (/ 32.0 icon-size) :scale (/ (float (frame-char-height)) icon-size) )))) ;; ("firefox-esr.desktop" "gnome-paint.desktop" "org.gnome.Nautilus.desktop" "org.gnome.Terminal.desktop" "org.gnome.Screenshot.desktop") (defcustom exwm-preferred-apps nil "Preferred apps" :type `(set ,@(mapcar (lambda (app) (list 'string app)) (sort (mapcar #'car exwm-apps) #'string<)))) ;; (("firefox-esr.desktop" image :type png :file "/usr/share/icons/hicolor/128x128/apps/firefox-esr.png" :scale 0.25) ;; ("gnome-paint.desktop") ;; ("org.gnome.Nautilus.desktop" image :type svg :file "/usr/share/icons/hicolor/scalable/apps/org.gnome.Nautilus.svg" :scale 0.25) ;; ("org.gnome.Terminal.desktop" image :type png :file "/usr/share/icons/Adwaita/16x16/apps/utilities-terminal.png" :scale 2.0) ;; ("org.gnome.Screenshot.desktop" image :type png :file "/usr/share/icons/Adwaita/16x16/apps/applets-screenshooter.png" :scale 2.0)) (setq exwm-app-launchers (cl-loop for app in exwm-preferred-apps collect (cons app (exwm-find-icon-file (gethash "Icon" (xdg-desktop-read-file (assoc-default app exwm-apps))))))) (defcustom exwm-panel-string-launchers (cl-loop for (desktop-file . icon-file) in exwm-app-launchers concat (when icon-file (concat (propertize " " 'keymap (let ((map (make-sparse-keymap))) (define-key map [mouse-1] `(lambda () (interactive) (call-process "gtk-launch" nil 0 nil ,desktop-file))) map) 'display icon-file 'mouse-face 'mode-line-highlight) " "))) "Launchers.") (defvar exwm-panel-string nil) (defun exwm-panel--get-buffer () (get-buffer-create " *exwm-panel*")) (easy-menu-define exwm-workspace-menu nil "Menu for Exwm Workspace. Also used in `exwm-mode-line-workspace-map'." '("Exwm Workspace" ["Add workspace" exwm-workspace-add] ["Delete current workspace" exwm-workspace-delete] ["Move workspace to" exwm-workspace-move] ["Swap workspaces" exwm-workspace-swap] ["Move X window to" exwm-workspace-move-window] ["Move X window from" exwm-workspace-switch-to-buffer] ["Toggle minibuffer" exwm-workspace-toggle-minibuffer] ["Switch workspace" exwm-workspace-switch] ;; Place this entry at bottom to avoid selecting others by accident. ("Switch to" :filter (lambda (&rest _args) (mapcar (lambda (i) `[,(format "workspace %d" i) (lambda () (interactive) (exwm-workspace-switch ,i)) (/= ,i exwm-workspace-current-index)]) (number-sequence 0 (1- (exwm-workspace--count)))))))) (defun exwm-panel-string--update () (setq exwm-panel-string (concat exwm-panel-string-launchers " " (mapconcat (lambda (i) (propertize (format "%d" i) 'keymap (let ((map (make-sparse-keymap))) (define-key map [mouse-1] `(lambda () (interactive) (exwm-workspace-switch ,i))) (define-key map [mouse-3] exwm-workspace-menu) map) 'face (when (= i exwm-workspace-current-index) 'mode-line-highlight) 'display (when nil (let ((current-workspace-icon (create-image "/usr/share/icons/gnome/16x16/devices/computer.png" nil nil)) (other-workspace-icon (create-image "/usr/share/icons/gnome/16x16/devices/computer.png" nil nil :conversion 'disabled))) (if (= i exwm-workspace-current-index) current-workspace-icon other-workspace-icon))) 'help-echo (format "mouse-1: Switch to %s\n\mouse-3: EXWM Workspace menu" (funcall exwm-workspace-index-map i)) 'mouse-face 'mode-line-highlight)) (number-sequence 0 (1- (exwm-workspace--count))) " "))) ;; Show the string in posframe (posframe-show (exwm-panel--get-buffer) :string exwm-panel-string :poshandler #'posframe-poshandler-frame-top-right-corner) ;; Show the string in EXWM's panel (let ((window (frame-root-window exwm-workspace--panel))) (set-window-buffer window (with-current-buffer (exwm-panel--get-buffer) (erase-buffer) (insert exwm-panel-string) (current-buffer)))) (exwm-workspace--update-panel-height) (exwm-workspace--resize-panel-frame) (exwm-workspace--show-panel)) (add-hook 'exwm-workspace-switch-hook 'exwm-panel-string--update) (add-hook 'exwm-workspace-list-change-hook 'exwm-panel-string--update) (exwm-panel-string--update) (provide 'exwm-panel-string)