tweak(lib): interactively set opacity for current and future frames by lattarov · Pull Request #8395 · doomemacs/doomemacs · GitHub | Latest TMZ Celebrity News & Gossip | Watch TMZ Live
Skip to content

tweak(lib): interactively set opacity for current and future frames #8395

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

lattarov
Copy link

@lattarov lattarov commented May 17, 2025

Context

I use Emacs in daemon mode and wanted a way to set opacity to all new Emacs frames as soon as they're spawned.

Analysis

doom/set-frame-opacity only sets the current frame's opacity, but all new frames are not affected by it, and I couldn't find any other readily available way to do so.

I found two workarounds:

  1. adding a hook server-after-make-frame-hook in config.el:

(add-hook! 'server-after-make-frame-hook (doom/set-frame-opacity opacity))

Would be a nice addition to the documentation somewhere in the UI readme's FAQ, but from what I gathered docs are DNP until the doom modules refactor is finished.

  1. Change doom/set-frame-opacity so that it affects all frames
    Proposed by this PR.

Previous work on opacity handling

Testing

Tested on PopOS 22.04, Wayland session.


  • [ x] I searched the issue tracker and this hasn't been PRed before.
  • [ x] My changes are not on the do-not-PR list for this project.
  • [ x] My commits conform to Doom's git conventions.
  • My changes are visual; I've included before and after screenshots.
  • I am blindly checking these off.
  • [x ] Any relevant issues or PRs have been linked to.
  • [x ] This a draft PR; I need more time to finish it.

@lattarov lattarov changed the title feat(ui): doom/set-frame-opacity for all frames feat(lib): set opacity for current and new frames May 17, 2025
@lattarov lattarov changed the title feat(lib): set opacity for current and new frames tweak(lib): set opacity for current and new frames May 17, 2025
@lattarov lattarov marked this pull request as ready for review May 17, 2025 15:34
@lattarov lattarov requested a review from a team as a code owner May 17, 2025 15:34
@hlissner
Copy link
Member

hlissner commented May 17, 2025

doom/set-frame-opacity exists for changing the opacity of a frame interactively. I'll consider extending it to operate on all current (and future) frames if passed the prefix argument:

(defun doom/set-frame-opacity (opacity &optional all-frames?)
  "Interactively change the current frame's opacity.

OPACITY is an integer between 0 to 100, inclusive. If ALL-FRAMES? is non-nil,
apply this to all existing frames, as well as future frames."
  (interactive (list 'interactive current-prefix-arg))
  (let* ((parameter
          (if (eq window-system 'pgtk)
              'alpha-background
            'alpha))
         (opacity
          (if (eq opacity 'interactive)
              (read-number "Opacity (0-100): "
                           (or (frame-parameter nil parameter)
                               100))
            opacity)))
    (if (not all-frames?)
        (set-frame-parameter nil parameter opacity)
      (modify-all-frames-parameters (cons parameter opacity))
      (setf (alist-get parameter default-frame-alist) opacity))))

However, from the way you describe it, default-frame-alist is better suited to your purpose:

;;; add to $DOOMDIR/config.el
(add-to-list 'default-frame-alist '(alpha-background . 95))

Interactive commands (any command whose name is formatted as foo/bar) aren't intended to be used directly from elisp, in any case.

@hlissner hlissner added is:feature Adds or requests new features, or extends existing ones module:core:lib Relevant to Doom core's libraries was:moved Is, was, or will be addressed elsewhere labels May 17, 2025
@hlissner hlissner added this to the core v3.0 milestone May 17, 2025
@hlissner hlissner marked this pull request as draft May 17, 2025 15:51
@lattarov lattarov force-pushed the master branch 2 times, most recently from 085f2ef to 84ee9eb Compare May 17, 2025 20:43
@lattarov lattarov changed the title tweak(lib): set opacity for current and new frames tweak(lib): interactively set opacity for current and new frames May 17, 2025
@lattarov lattarov changed the title tweak(lib): interactively set opacity for current and new frames tweak(lib): interactively set opacity for current and future frames May 17, 2025
@lattarov lattarov force-pushed the master branch 2 times, most recently from dcd4f9a to 4dee5ed Compare May 17, 2025 20:59
@lattarov
Copy link
Author

lattarov commented May 17, 2025

@hlissner Thanks a lot for the feedback!

Directly changing alpha-background in default-frame-alist is indeed the best solution specifically for my problem.

The snippet you sent with the new API for defun doom/set-frame-opacity (opacity &optional all-frames?) correctly sets the opacity for the current frame, but no effect on new frames.

After some digging, I noticed that alpha-background is not set in default-frame-alist in new frames. Traceback & doom info below:

Evaluating emacs-lisp (doom/set-frame-opacity 70 t) resulted in:

Debugger entered--Lisp error: (wrong-type-argument listp (alpha-background . 70))
  modify-all-frames-parameters((alpha-background . 70))
  (if (not all-frames?) (set-frame-parameter nil parameter opacity) (modify-all-frames-parameters (cons parameter opacity)) (let* ((p (assq parameter default-frame-alist)) (v opacity)) (progn (if p (setcdr p v) (setq default-frame-alist (cons (setq p (cons parameter v)) default-frame-alist))) v)))
  (let* ((parameter (if (eq window-system 'pgtk) 'alpha-background 'alpha)) (opacity (if (eq opacity 'interactive) (read-number "Opacity (0-100): " (or (frame-parameter nil parameter) 100)) opacity))) (if (not all-frames?) (set-frame-parameter nil parameter opacity) (modify-all-frames-parameters (cons parameter opacity)) (let* ((p (assq parameter default-frame-alist)) (v opacity)) (progn (if p (setcdr p v) (setq default-frame-alist (cons (setq p ...) default-frame-alist))) v))))
  doom/set-frame-opacity(70 t)
  eval-region(298 328 #<buffer  *+eval-output*> read)  ; Reading at buffer position 298
  (let ((doom-context doom-context)) (doom-context-push 'eval) (eval-region beg end buffer load-read-function))
  (let ((doom-module-context (let ((key (doom-module-from-path (or ... default-directory)))) (if key (doom-module-context key) (let ((index nil) (key nil) (path nil) (flags nil) (features nil)) (progn (record ... index key path flags features))))))) (if (and (not doom-inhibit-log) (or (not noninteractive) (<= 2 doom-log-level))) (progn (doom--log 2 ":context:module: =%s" doom-module-context))) (let ((doom-context doom-context)) (doom-context-push 'eval) (eval-region beg end buffer load-read-function)) (save-current-buffer (set-buffer buffer) (let ((pp-max-width nil)) (require 'pp) (pp-buffer) (replace-regexp-in-string "\\\\n" "\n" (string-trim-left (buffer-string))))))
  (condition-case e (let ((doom-module-context (let ((key (doom-module-from-path ...))) (if key (doom-module-context key) (let (... ... ... ... ...) (progn ...)))))) (if (and (not doom-inhibit-log) (or (not noninteractive) (<= 2 doom-log-level))) (progn (doom--log 2 ":context:module: =%s" doom-module-context))) (let ((doom-context doom-context)) (doom-context-push 'eval) (eval-region beg end buffer load-read-function)) (save-current-buffer (set-buffer buffer) (let ((pp-max-width nil)) (require 'pp) (pp-buffer) (replace-regexp-in-string "\\\\n" "\n" (string-trim-left (buffer-string)))))) ((debug error) (format "ERROR: %s" e)))
  (unwind-protect (condition-case e (let ((doom-module-context (let ((key ...)) (if key (doom-module-context key) (let ... ...))))) (if (and (not doom-inhibit-log) (or (not noninteractive) (<= 2 doom-log-level))) (progn (doom--log 2 ":context:module: =%s" doom-module-context))) (let ((doom-context doom-context)) (doom-context-push 'eval) (eval-region beg end buffer load-read-function)) (save-current-buffer (set-buffer buffer) (let ((pp-max-width nil)) (require 'pp) (pp-buffer) (replace-regexp-in-string "\\\\n" "\n" (string-trim-left (buffer-string)))))) ((debug error) (format "ERROR: %s" e))) (kill-buffer buffer))
  (save-current-buffer (set-buffer working-buffer) (unwind-protect (condition-case e (let ((doom-module-context (let (...) (if key ... ...)))) (if (and (not doom-inhibit-log) (or (not noninteractive) (<= 2 doom-log-level))) (progn (doom--log 2 ":context:module: =%s" doom-module-context))) (let ((doom-context doom-context)) (doom-context-push 'eval) (eval-region beg end buffer load-read-function)) (save-current-buffer (set-buffer buffer) (let ((pp-max-width nil)) (require 'pp) (pp-buffer) (replace-regexp-in-string "\\\\n" "\n" (string-trim-left ...))))) ((debug error) (format "ERROR: %s" e))) (kill-buffer buffer)))
  (let ((buffer (generate-new-buffer " *+eval-output*")) (working-buffer (or +emacs-lisp-eval-working-buffer (current-buffer))) (debug-on-error t)) (if (buffer-live-p working-buffer) nil (progn (setq +emacs-lisp-eval-working-buffer nil) (setq working-buffer (current-buffer)))) (save-current-buffer (set-buffer working-buffer) (unwind-protect (condition-case e (let ((doom-module-context (let ... ...))) (if (and (not doom-inhibit-log) (or ... ...)) (progn (doom--log 2 ":context:module: =%s" doom-module-context))) (let ((doom-context doom-context)) (doom-context-push 'eval) (eval-region beg end buffer load-read-function)) (save-current-buffer (set-buffer buffer) (let (...) (require ...) (pp-buffer) (replace-regexp-in-string "\\\\n" "\n" ...)))) ((debug error) (format "ERROR: %s" e))) (kill-buffer buffer))))
  (string-trim-right (let ((buffer (generate-new-buffer " *+eval-output*")) (working-buffer (or +emacs-lisp-eval-working-buffer (current-buffer))) (debug-on-error t)) (if (buffer-live-p working-buffer) nil (progn (setq +emacs-lisp-eval-working-buffer nil) (setq working-buffer (current-buffer)))) (save-current-buffer (set-buffer working-buffer) (unwind-protect (condition-case e (let ((doom-module-context ...)) (if (and ... ...) (progn ...)) (let (...) (doom-context-push ...) (eval-region beg end buffer load-read-function)) (save-current-buffer (set-buffer buffer) (let ... ... ... ...))) ((debug error) (format "ERROR: %s" e))) (kill-buffer buffer)))))
  (+eval-display-results (string-trim-right (let ((buffer (generate-new-buffer " *+eval-output*")) (working-buffer (or +emacs-lisp-eval-working-buffer (current-buffer))) (debug-on-error t)) (if (buffer-live-p working-buffer) nil (progn (setq +emacs-lisp-eval-working-buffer nil) (setq working-buffer (current-buffer)))) (save-current-buffer (set-buffer working-buffer) (unwind-protect (condition-case e (let (...) (if ... ...) (let ... ... ...) (save-current-buffer ... ...)) ((debug error) (format "ERROR: %s" e))) (kill-buffer buffer))))) (current-buffer))
  +emacs-lisp-eval(298 328)
  funcall(+emacs-lisp-eval 298 328)
  (if runner (funcall runner beg end) (let ((quickrun-option-cmdkey lang)) (quickrun-region beg end)))
  (let* ((runner (and t (or (alist-get runner-major-mode +eval-runners) (and (require 'quickrun nil t) (equal (setq lang ...) "emacs") (alist-get 'emacs-lisp-mode +eval-runners)))))) (if runner (funcall runner beg end) (let ((quickrun-option-cmdkey lang)) (quickrun-region beg end))))
  (let (lang) (let* ((runner (and t (or (alist-get runner-major-mode +eval-runners) (and (require ... nil t) (equal ... "emacs") (alist-get ... +eval-runners)))))) (if runner (funcall runner beg end) (let ((quickrun-option-cmdkey lang)) (quickrun-region beg end)))))
  (cond ((if (fboundp '+eval--ensure-in-repl-buffer) (condition-case nil (progn (get-buffer-window (or (+eval--ensure-in-repl-buffer) t))) (error nil))) (funcall (or (plist-get (cdr (alist-get runner-major-mode +eval-repls)) :send-region) #'+eval/send-region-to-repl) beg end)) ((let (lang) (let* ((runner (and t (or ... ...)))) (if runner (funcall runner beg end) (let ((quickrun-option-cmdkey lang)) (quickrun-region beg end)))))))
  (let ((load-file-name buffer-file-name) (load-true-file-name (or buffer-file-truename (if buffer-file-name (file-truename buffer-file-name)))) (runner-major-mode (or runner-major-mode major-mode))) (cond ((if (fboundp '+eval--ensure-in-repl-buffer) (condition-case nil (progn (get-buffer-window (or ... t))) (error nil))) (funcall (or (plist-get (cdr (alist-get runner-major-mode +eval-repls)) :send-region) #'+eval/send-region-to-repl) beg end)) ((let (lang) (let* ((runner (and t ...))) (if runner (funcall runner beg end) (let (...) (quickrun-region beg end))))))))
  +eval-region-as-major-mode(298 328)
  +eval/region(298 328)
  (if (and evil-inhibit-operator (called-interactively-p 'any)) nil (+eval/region beg end))
  (let ((evil-inhibit-operator evil-inhibit-operator-value) (end-marker (make-marker))) (set-marker end-marker end) (if (and evil-inhibit-operator (called-interactively-p 'any)) nil (+eval/region beg end)) (evil-set-marker 91 (or beg (point-max))) (evil-set-marker 93 (max (or beg (point-max)) (1- (or (marker-position end-marker) (point-max))))) (set-marker end-marker nil))
  (unwind-protect (let ((evil-inhibit-operator evil-inhibit-operator-value) (end-marker (make-marker))) (set-marker end-marker end) (if (and evil-inhibit-operator (called-interactively-p 'any)) nil (+eval/region beg end)) (evil-set-marker 91 (or beg (point-max))) (evil-set-marker 93 (max (or beg (point-max)) (1- (or (marker-position end-marker) (point-max))))) (set-marker end-marker nil)) (setq evil-inhibit-operator-value nil))
  #f(lambda (beg end) [t] "Evaluate selection or sends it to the open REPL, if available." (interactive (let* ((props (evil-command-properties '+eval:region)) (evil-operator-range-motion (let ((p (plist-member props :motion))) (if p (progn (or (car (cdr p)) #'undefined))))) (evil-operator-range-type (plist-get props :type)) evil-operator-range-beginning evil-operator-range-end evil-inhibit-operator) (progn (setq evil-inhibit-operator-value nil) (setq evil-this-operator this-command) (setq evil-operator-start-col (current-column))) (prog1 (evil-operator-range) (setq evil-inhibit-operator-value evil-inhibit-operator) (if nil (if (evil-visual-state-p) (progn (evil-visual-expand-region))) (setq deactivate-mark t)) (cond ((evil-visual-state-p) (evil-visual-rotate 'upper-left)) ((plist-get props :move-point) (if evil-operator-range-beginning (progn (goto-char evil-operator-range-beginning)))))))) (unwind-protect (let ((evil-inhibit-operator evil-inhibit-operator-value) (end-marker (make-marker))) (set-marker end-marker end) (if (and evil-inhibit-operator (called-interactively-p 'any)) nil (+eval/region beg end)) (evil-set-marker 91 (or beg (point-max))) (evil-set-marker 93 (max (or beg (point-max)) (1- (or (marker-position end-marker) (point-max))))) (set-marker end-marker nil)) (setq evil-inhibit-operator-value nil)))(298 328)
  apply(#f(lambda (beg end) [t] "Evaluate selection or sends it to the open REPL, if available." (interactive (let* ((props (evil-command-properties '+eval:region)) (evil-operator-range-motion (let (...) (if p ...))) (evil-operator-range-type (plist-get props :type)) evil-operator-range-beginning evil-operator-range-end evil-inhibit-operator) (progn (setq evil-inhibit-operator-value nil) (setq evil-this-operator this-command) (setq evil-operator-start-col (current-column))) (prog1 (evil-operator-range) (setq evil-inhibit-operator-value evil-inhibit-operator) (if nil (if (evil-visual-state-p) (progn ...)) (setq deactivate-mark t)) (cond ((evil-visual-state-p) (evil-visual-rotate ...)) ((plist-get props :move-point) (if evil-operator-range-beginning ...)))))) (unwind-protect (let ((evil-inhibit-operator evil-inhibit-operator-value) (end-marker (make-marker))) (set-marker end-marker end) (if (and evil-inhibit-operator (called-interactively-p 'any)) nil (+eval/region beg end)) (evil-set-marker 91 (or beg (point-max))) (evil-set-marker 93 (max (or beg (point-max)) (1- (or ... ...)))) (set-marker end-marker nil)) (setq evil-inhibit-operator-value nil))) (298 328))
  +eval:region(298 328)
  funcall-interactively(+eval:region 298 328)
  command-execute(+eval:region)
generated  May 17, 2025 19:04:40
system     Pop!_OS 22.04 LTS Linux 6.12.10-76061203-generic x86_64
emacs      30.1 EMACSDIR=~/.config/emacs/ EMACS=/usr/local/bin/emacs
doom       3.0.0-pre PROFILE=_default@0 HEAD -> master b70d137f 2025-05-06 01:39:11
	   -0400 ~/.config/doom/
shell      /bin/bash
features   ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ
	   IMAGEMAGICK JPEG LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 MODULES
	   NATIVE_COMP NOTIFY INOTIFY PDUMPER PGTK PNG RSVG SECCOMP SOUND SQLITE3
	   THREADS TIFF TOOLKIT_SCROLL_BARS TREE_SITTER XIM GTK3 ZLIB
traits     batch server-running envvar-file custom-file
modules    :config use-package :input (layout +azerty) :completion (corfu +orderless
	   +icons) (vertico +icons +childframe) :ui doom doom-dashboard hl-todo
	   indent-guides ligatures modeline nav-flash ophints (popup +defaults) unicode
	   (vc-gutter +pretty) window-select workspaces :editor (evil +everywhere)
	   file-templates fold (format +onsave) multiple-cursors rotate-text snippets
	   word-wrap :emacs (dired +icons +dirvish) electric (ibuffer +icons) undo :term
	   vterm :checkers syntax (spell +flyspell) grammar :tools (debugger +lsp) ein
	   (eval +overlay) lookup (lsp +peek) magit pdf tree-sitter :lang (cc +lsp
	   +tree-sitter) emacs-lisp markdown (org +brain +roam2 +pretty +present
	   +pomodoro +dragndrop +journal +brain) plantuml (python +lsp +conda +ein
	   +tree-sitter) (rust +lsp +tree-sitter) sh :email (mu4e +org +gmail) :app
	   calendar everywhere (rss +org) :config literate (default +bindings
	   +smartparens)
packages   (catppuccin-theme) (olivetti) (org-roam-ui) (org-modern) (cmake-ide) (gptel)
	   (bug-hunter) (consult-omni :type 'core :recipe '(:host github :repo
	   armindarvish/consult-omni :files (sources/*.el consult-omni.el
	   consult-omni-embark.el) :build t)) (compiler-explorer :recipe '(:host github
	   :repo mkcms/compiler-explorer.el :build t)) (devdocs) (spotify) (multi-vterm)
	   (whisper.el :recipe '(:host github :repo natrys/whisper.el))
elpa       with-editor wfnames systemd helm-systemd helm-core helm async

I didn't know about the convention for the foo/bar functions. In that's the case and while we're at it, shouldn't we prompt the user for the all-frames? case? I adapted your version of the function to take that into consideration:

(defun doom/set-frame-opacity (opacity &optional all-frames?)
  "Interactively change the current and all new frames' opacity.

OPACITY is an integer between 0 to 100, inclusive. If nil, prompt user
for value and if it should be applied to future frames.

ALL-FRAMES? is an optional that if non-nil defines sets OPACITY to all
future frames."
  (interactive '(interactive))
  (setq prompt-user? (eq opacity 'interactive))
  (let* ((parameter
          (if (eq window-system 'pgtk)
              'alpha-background
            'alpha))
         (opacity
          (if prompt-user?
              (read-number "Opacity (0-100): "
                           (or (frame-parameter nil parameter)
                               100))
            opacity)))

    ;; current frame
    (set-frame-parameter nil parameter opacity)

    (if prompt-user?
        (setq all-frames? (y-or-n-p (format "Apply opacity %d to all future frames? " opacity))))

    ;; future frames
    (if all-frames?
        (setf (alist-get parameter default-frame-alist) opacity)
      (modify-all-frames-parameters `((,parameter . ,opacity))))))

Improves doom/set-frame-opacity by adding 2 non-conflicting ways of
setting the opacity for new frames.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
is:feature Adds or requests new features, or extends existing ones module:core:lib Relevant to Doom core's libraries was:moved Is, was, or will be addressed elsewhere
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants

TMZ Celebrity News – Breaking Stories, Videos & Gossip

Looking for the latest TMZ celebrity news? You've come to the right place. From shocking Hollywood scandals to exclusive videos, TMZ delivers it all in real time.

Whether it’s a red carpet slip-up, a viral paparazzi moment, or a legal drama involving your favorite stars, TMZ news is always first to break the story. Stay in the loop with daily updates, insider tips, and jaw-dropping photos.

🎥 Watch TMZ Live

TMZ Live brings you daily celebrity news and interviews straight from the TMZ newsroom. Don’t miss a beat—watch now and see what’s trending in Hollywood.