From a9218189150521687b72c37ff27ed3e4956e6194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20Schwarz=C3=A4ugl?= Date: Tue, 22 Jul 2025 08:49:31 +0200 Subject: [PATCH] feat: add popup frame from emacs --- SwarselSystems.org | 51 +++++++++++++++++++++++++++++++++--- files/emacs/init.el | 38 +++++++++++++++++++++++++++ modules/home/common/sway.nix | 8 +++--- 3 files changed, 91 insertions(+), 6 deletions(-) diff --git a/SwarselSystems.org b/SwarselSystems.org index 364adfa..de8a276 100644 --- a/SwarselSystems.org +++ b/SwarselSystems.org @@ -12851,8 +12851,6 @@ Currently, I am too lazy to explain every option here, but most of it is very se "${modifier}+Space" = "exec fuzzel"; "${modifier}+Shift+Space" = "floating toggle"; "${modifier}+e" = "exec emacsclient -nquc -a emacs -e \"(dashboard-open)\""; - "${modifier}+Shift+m" = "exec emacsclient -nquc -a emacs -e \"(mu4e)\""; - "${modifier}+Shift+c" = "exec emacsclient -nquc -a emacs -e \"(swarsel/open-calendar)\""; "${modifier}+m" = "exec swaymsg workspace back_and_forth"; "${modifier}+a" = "exec swarselcheck -s"; "${modifier}+x" = "exec swarselcheck -k"; @@ -12861,7 +12859,10 @@ Currently, I am too lazy to explain every option here, but most of it is very se "${modifier}+Shift+t" = "exec opacitytoggle"; "${modifier}+Shift+F12" = "move scratchpad"; "${modifier}+F12" = "scratchpad show"; - "${modifier}+c" = "exec qalculate-gtk"; + "${modifier}+Shift+c" = "exec qalculate-gtk"; + "${modifier}+c" = "emacsclient -e '(prot-window-popup-org-capture)'"; + "${modifier}+Shift+m" = "emacsclient -e '(prot-window-popup-mu4e)'"; + "${modifier}+Shift+a" = "emacsclient -e '(prot-window-popup-swarsel/open-calendar)'"; "${modifier}+p" = "exec pass-fuzzel"; "${modifier}+o" = "exec pass-fuzzel --otp"; "${modifier}+Shift+p" = "exec pass-fuzzel --type"; @@ -12994,6 +12995,7 @@ Currently, I am too lazy to explain every option here, but most of it is very se { title = "^Add$"; } { title = "^Picture-in-Picture$"; } { title = "Syncthing Tray"; } + { title = "Emacs Popup Frame"; } { title = "^spotifytui$"; } { title = "^kittyterm$"; } { app_id = "vesktop"; } @@ -20174,6 +20176,49 @@ This sets up the =dashboard=, which is really quite useless. But, it looks cool (add-hook 'comint-output-filter-functions 'comint-truncate-buffer) #+end_src +*** Popup frames + +#+begin_src emacs-lisp + (defun prot-window-delete-popup-frame (&rest _) + "Kill selected selected frame if it has parameter `prot-window-popup-frame'. + Use this function via a hook." + (when (frame-parameter nil 'prot-window-popup-frame) + (delete-frame))) + + (defmacro prot-window-define-with-popup-frame (command) + "Define interactive function which calls COMMAND in a new frame. + Make the new frame have the `prot-window-popup-frame' parameter." + `(defun ,(intern (format "prot-window-popup-%s" command)) () + ,(format "Run `%s' in a popup frame with `prot-window-popup-frame' parameter. + Also see `prot-window-delete-popup-frame'." command) + (interactive) + (let ((frame (make-frame '((prot-window-popup-frame . t))))) + (select-frame frame) + (modify-frame-parameters nil '((title . "Emacs Popup Frame"))) + (switch-to-buffer " prot-window-hidden-buffer-for-popup-frame") + (condition-case nil + (call-interactively ',command) + ((quit error user-error) + (delete-frame frame)))))) + + (declare-function org-capture "org-capture" (&optional goto keys)) + (defvar org-capture-after-finalize-hook) + ;;;###autoload (autoload 'prot-window-popup-org-capture "prot-window") + (prot-window-define-with-popup-frame org-capture) + (add-hook 'org-capture-after-finalize-hook #'prot-window-delete-popup-frame) + + (declare-function mu4e "mu4e" (&optional goto keys)) + ;;;###autoload (autoload 'prot-window-popup-mu4e "prot-window") + (prot-window-define-with-popup-frame mu4e) + (advice-add 'mu4e-quit :after #'prot-window-delete-popup-frame) + + (declare-function swarsel/open-calendar "swarsel/open-calendar" (&optional goto keys)) + ;;;###autoload (autoload 'prot-window-popup-swarsel/open-calendar "prot-window") + (prot-window-define-with-popup-frame swarsel/open-calendar) + (advice-add 'bury-buffer :after #'prot-window-delete-popup-frame) + +#+end_src + * Appendix A: Noweb-Ref blocks :PROPERTIES: :CUSTOM_ID: h:dae0c5bb-edb7-4fe4-ae31-9f8f064cc53c diff --git a/files/emacs/init.el b/files/emacs/init.el index 4c024ee..d9c090a 100644 --- a/files/emacs/init.el +++ b/files/emacs/init.el @@ -1709,3 +1709,41 @@ create a new one." (setq message-log-max 30) (setq comint-buffer-maximum-size 50) (add-hook 'comint-output-filter-functions 'comint-truncate-buffer) + +(defun prot-window-delete-popup-frame (&rest _) + "Kill selected selected frame if it has parameter `prot-window-popup-frame'. +Use this function via a hook." + (when (frame-parameter nil 'prot-window-popup-frame) + (delete-frame))) + +(defmacro prot-window-define-with-popup-frame (command) + "Define interactive function which calls COMMAND in a new frame. +Make the new frame have the `prot-window-popup-frame' parameter." + `(defun ,(intern (format "prot-window-popup-%s" command)) () + ,(format "Run `%s' in a popup frame with `prot-window-popup-frame' parameter. +Also see `prot-window-delete-popup-frame'." command) + (interactive) + (let ((frame (make-frame '((prot-window-popup-frame . t))))) + (select-frame frame) + (modify-frame-parameters nil '((title . "Emacs Popup Frame"))) + (switch-to-buffer " prot-window-hidden-buffer-for-popup-frame") + (condition-case nil + (call-interactively ',command) + ((quit error user-error) + (delete-frame frame)))))) + +(declare-function org-capture "org-capture" (&optional goto keys)) +(defvar org-capture-after-finalize-hook) +;;;###autoload (autoload 'prot-window-popup-org-capture "prot-window") +(prot-window-define-with-popup-frame org-capture) +(add-hook 'org-capture-after-finalize-hook #'prot-window-delete-popup-frame) + +(declare-function mu4e "mu4e" (&optional goto keys)) +;;;###autoload (autoload 'prot-window-popup-mu4e "prot-window") +(prot-window-define-with-popup-frame mu4e) +(advice-add 'mu4e-quit :after #'prot-window-delete-popup-frame) + +(declare-function swarsel/open-calendar "swarsel/open-calendar" (&optional goto keys)) +;;;###autoload (autoload 'prot-window-popup-swarsel/open-calendar "prot-window") +(prot-window-define-with-popup-frame swarsel/open-calendar) +(advice-add 'bury-buffer :after #'prot-window-delete-popup-frame) diff --git a/modules/home/common/sway.nix b/modules/home/common/sway.nix index 3dd5363..bb429dc 100644 --- a/modules/home/common/sway.nix +++ b/modules/home/common/sway.nix @@ -117,8 +117,6 @@ in "${modifier}+Space" = "exec fuzzel"; "${modifier}+Shift+Space" = "floating toggle"; "${modifier}+e" = "exec emacsclient -nquc -a emacs -e \"(dashboard-open)\""; - "${modifier}+Shift+m" = "exec emacsclient -nquc -a emacs -e \"(mu4e)\""; - "${modifier}+Shift+c" = "exec emacsclient -nquc -a emacs -e \"(swarsel/open-calendar)\""; "${modifier}+m" = "exec swaymsg workspace back_and_forth"; "${modifier}+a" = "exec swarselcheck -s"; "${modifier}+x" = "exec swarselcheck -k"; @@ -127,7 +125,10 @@ in "${modifier}+Shift+t" = "exec opacitytoggle"; "${modifier}+Shift+F12" = "move scratchpad"; "${modifier}+F12" = "scratchpad show"; - "${modifier}+c" = "exec qalculate-gtk"; + "${modifier}+Shift+c" = "exec qalculate-gtk"; + "${modifier}+c" = "emacsclient -e '(prot-window-popup-org-capture)'"; + "${modifier}+Shift+m" = "emacsclient -e '(prot-window-popup-mu4e)'"; + "${modifier}+Shift+a" = "emacsclient -e '(prot-window-popup-swarsel/open-calendar)'"; "${modifier}+p" = "exec pass-fuzzel"; "${modifier}+o" = "exec pass-fuzzel --otp"; "${modifier}+Shift+p" = "exec pass-fuzzel --type"; @@ -260,6 +261,7 @@ in { title = "^Add$"; } { title = "^Picture-in-Picture$"; } { title = "Syncthing Tray"; } + { title = "Emacs Popup Frame"; } { title = "^spotifytui$"; } { title = "^kittyterm$"; } { app_id = "vesktop"; }