Emacs 透明窗口

看到上面的帖子之后我忽然想起来,似乎Emacs可以设置窗口透明度。 然后我找到个很好的小工具:让你的Eamcs窗口临时变透明。先上效果图。

这个功能不但很装逼,而且在一些特定的场景下也很有用。

因为原网站没有代码格式化,我就把代码贴上了。

;;; config-alpha.el ---

;; Copyright 2013 Scinart Ouyang
;;
;; Author: [email protected]
;; Version: $Id: my-alpha.el,v 0.0 2013/06/03 12:22:42 scinart Exp $
;; Keywords:
;; X-URL: not distributed yet

;; 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 2, 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, write to the Free Software
;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

;;; Code:


(defvar frame-alpha-active-walk-step 2)
(defvar frame-alpha-inactive-walk-step 1)
(defvar frame-alpha-default (list 100 50))

(defconst frame-alpha-original-lower-limit 20)

(setq frame-alpha-lower-limit 10)
(defvar frame-alpha-max 100)
(defvar frame-alpha-min frame-alpha-lower-limit)

(defun frame-alpha-initialize ()
  (set-frame-parameter nil 'alpha (or (frame-parameter nil 'alpha) frame-alpha-default)))
;; important
(frame-alpha-initialize)

(defun frame-alpha-set-active (arg)
  (cond ((> arg frame-alpha-max)
     (dolist (f (frame-list))
       (set-frame-parameter f 'alpha (list frame-alpha-max (second (frame-parameter nil 'alpha))))))
    ((< arg frame-alpha-min)
     (dolist (f (frame-list))
       (set-frame-parameter f 'alpha (list frame-alpha-min (second (frame-parameter nil 'alpha))))))
    (t
     (dolist (f (frame-list))
       (set-frame-parameter f 'alpha (list arg (second (frame-parameter nil 'alpha))))))))
(defun frame-alpha-get-active ()
  (first (frame-parameter nil 'alpha)))

(defun frame-alpha-set-inactive (arg)
  (cond ((> arg frame-alpha-max)
     (dolist (f (frame-list))
       (set-frame-parameter f 'alpha (list (first (frame-parameter nil 'alpha)) frame-alpha-max))))
    ((< arg frame-alpha-min)
     (dolist (f (frame-list))
       (set-frame-parameter f 'alpha (list (first (frame-parameter nil 'alpha)) frame-alpha-min))))
    (t
     (dolist (f (frame-list))
       (set-frame-parameter f 'alpha (list (first (frame-parameter nil 'alpha)) arg))))))
(defun frame-alpha-get-inactive ()
  (second (frame-parameter nil 'alpha)))

(defun frame-alpha-set-all (arg)
  (if (and (list arg)
       (list (cdr arg))
       (null (cddr arg))
       (numberp (first arg))
       (numberp (second arg)))
      (progn
    (frame-alpha-set-active (first arg))
    (frame-alpha-set-inactive (second arg)))
    (message "%s in not a valid parameter like (100 80)" arg)))
(defun frame-alpha-get-all ()
  (frame-parameter nil 'alpha))

(defun frame-alpha-active-increase ()
  (interactive)
  (frame-alpha-set-active (+ (frame-alpha-get-active) frame-alpha-active-walk-step)))
(defun frame-alpha-active-decrease ()
  (interactive)
  (frame-alpha-set-active (- (frame-alpha-get-active) frame-alpha-active-walk-step)))
(defun frame-alpha-inactive-increase ()
  (interactive)
  (frame-alpha-set-inactive (+ (frame-alpha-get-inactive) frame-alpha-inactive-walk-step)))
(defun frame-alpha-inactive-decrease ()
  (interactive)
  (frame-alpha-set-inactive (- (frame-alpha-get-inactive) frame-alpha-inactive-walk-step)))
(defun frame-alpha-all-increase ()
  (frame-alpha-active-increase)
  (frame-alpha-inactive-increase))
(defun frame-alpha-all-decrease ()
  (frame-alpha-active-decrease)
  (frame-alpha-inactive-decrease))

(defun frame-alpha-get ()
  (interactive)
  (message "%s" (frame-parameter (selected-frame) 'alpha)))
(defun frame-alpha-reset ()
  (interactive)
  (set-frame-parameter (selected-frame) 'alpha frame-alpha-default))



;;;###autoload
(defun peek (arg)
  "Temporary set transparent to arg seconds."
  (interactive "p")
  (let ((alpha (car (frame-alpha-get-all)))
        (time (1+ (log (+ 1 (abs arg)) 4))))
    (when (< 50 alpha)
      (frame-alpha-set-active 33)
      (message "%d" time)
      (sleep-for (abs time) 500)
      (frame-alpha-set-active alpha))))

;;;###autoload
(defun perspective ()
  "be transparent until a key stroke
2013-06-06 Thursday 22:45:58 by Scinart"
  (interactive)
  (let ((active-alpha (frame-alpha-get-active))
        (inactive-alpha (frame-alpha-get-inactive)))
    (frame-alpha-set-active frame-alpha-min)
    (frame-alpha-set-inactive frame-alpha-min)
    (read-event)
    (when last-input-event
      (frame-alpha-set-active active-alpha)
      (frame-alpha-set-inactive inactive-alpha)
      (setq unread-command-events (list last-input-event)))))

(defadvice make-frame-command (around same-transparency activate compile)
  "Create a new frame with the same transparency."
  (interactive)
  (if (display-graphic-p)
      (make-frame (list (cons 'alpha (frame-parameter (selected-frame) 'alpha))))
    (select-frame (make-frame))))

(provide 'config-alpha)

你可以写在一个el文件里作为package加载。

这里窝用了multi-keys.el

(use-package config-alpha
  :defer t
  :init
  (multi-keys-define-global "qp" 'perspective)
  )

同时按q p,窗口透明了,COOL!!!

默认效果是让不活动的窗口变透明。


原帖:

7 个赞

看到又有个更简短的loop-alpha

;;set transparent effect
(global-set-key [(f11)] 'loop-alpha)
(setq alpha-list '((100 100) (95 65) (85 55) (75 45) (65 35)))
(defun loop-alpha ()
  (interactive)
  (let ((h (car alpha-list)))                ;; head value will set to
    ((lambda (a ab)
       (set-frame-parameter (selected-frame) 'alpha (list a ab))
       (add-to-list 'default-frame-alist (cons 'alpha (list a ab)))
       ) (car h) (car (cdr h)))
    (setq alpha-list (cdr (append alpha-list (list h))))
    )
)

不过还是觉得上面那个实现更具体一点。

2 个赞

spacemacs里自带了transparency的设置:joy:

1 个赞

SPC T T spacemacs/toggle-transparency 看了下具体实现,功能和loop-alpha差不多,似乎没有peek(暂时透明化几秒)和perspective(透明化直到下一个按键操作)那种实用功能。


然后这个功能还会和上面的代码冲突。考虑改造。

我是设置了默认打开transparency,调成95%才能勉强看清楚,其实并不用太花哨。 你要暂时透明化的话,它里面是有两个参数的,active and inactive transparency,设置下这两个参数,比方说一个95%,一个30%,然后用toggle-transparency 来回toggle

(defun peek (arg)
  "Temporary set transparent to arg seconds."
  (interactive "p")
  (let ((time (1+ (log (+ 1 (abs arg)) 4))))
    (unless (spacemacs/toggle-transparent-frame-p)
      (spacemacs/toggle-transparency))
    (message "%d sec" time)
    (sleep-for (abs time) 500)
    (spacemacs/toggle-transparency)))

(defun perspective ()
  "Be transparent until a key stroke."
  (interactive)
  (spacemacs/toggle-transparency)
  (read-event)
  (when last-input-event
    (spacemacs/toggle-transparency)
    (setq unread-command-events (list last-input-event))))

差不多这样。

用compiz窗口管理器的我……路过一下

The conflict to the Spacemacs is fixed, now here is the improved version.

;;; Code:


(defvar frame-alpha-default '(100 . 70)
  "The default value for active and inactive windows,
should be a cons cell.")

(defconst frame-alpha-original-lower-limit 20)

(setq frame-alpha-lower-limit 10)
(defvar frame-alpha-max 100)
(defvar frame-alpha-min frame-alpha-lower-limit
  "The alpha value for \"invisible\" frames.")

(defun frame-alpha-initialize ()
  "Must call this function to initialize frame-alpha."
  (set-frame-parameter nil 'alpha (or (frame-parameter nil 'alpha) frame-alpha-default)))
;; important
(frame-alpha-initialize)

(defun frame-alpha-set (type arg)
  "Set the frame alpha, TYPE can be \"active\", \"inactive\",
or \"all\". If TYPE is \"all\", ARG needs to be a cons cell,
otherwise ARG should be a number."
  (let ((alpha (unless (eq type 'all)
                 (cond ((> arg frame-alpha-max)
                        frame-alpha-max)
                       ((< arg frame-alpha-min)
                        frame-alpha-min)
                       (t arg)))))
    (dolist (f (frame-list))
      (set-frame-parameter
       f 'alpha (if (eq type 'all)
                    arg
                  (cons (if (eq type 'active) alpha
                          (car (frame-parameter nil 'alpha)))
                        (if (eq type 'inactive) alpha
                          (cdr (frame-parameter nil 'alpha)))))))))
(defun frame-alpha-get (type)
  "Get the frame alpha, TYPE can be \"active\", \"inactive\"
or \"all\"."
  (let ((alpha (frame-parameter nil 'alpha)))
    (cond
   ((eq type 'active)
    (car alpha))
   ((eq type 'inactive)
    (cdr alpha))
   ((eq type 'all)
    alpha))))

(defun frame-alpha-show ()
  (interactive)
  (message "%s" (frame-parameter (selected-frame) 'alpha)))
(defun frame-alpha-reset ()
  (interactive)
  (set-frame-parameter (selected-frame) 'alpha frame-alpha-default))



;;;###autoload
(defun peek (arg)
  "Temporary set transparent to ARG seconds."
  (interactive "p")
  (let ((alpha (car (frame-alpha-get 'all)))
        (time (1+ (log (+ 1 (abs arg)) 4))))
    (when (< 50 alpha)
      (frame-alpha-set 'active frame-alpha-min)
      (message "%d" time)
      (sleep-for (abs time) 500)
      (frame-alpha-set 'active alpha))))

;;;###autoload
(defun perspective ()
  "Be transparent until a key stroke."
  (interactive)
  (let ((alpha (frame-alpha-get 'all)))
    (frame-alpha-set 'all (cons frame-alpha-min frame-alpha-min))
    (read-event)
    (when last-input-event
      (frame-alpha-set 'all alpha)
      (setq unread-command-events (list last-input-event)))))

(defadvice make-frame-command (around same-transparency activate compile)
  "Create a new frame with the same transparency."
  (if (display-graphic-p)
      (make-frame (list (cons 'alpha (frame-parameter (selected-frame) 'alpha))))))

(provide 'config-transparency)

花时间改了一下,因为 Spacemacs 用了 cons cell 来设置 alpha,所以和原先的版本起冲突。我把不必要的部分去除了,然后精简了下函数。(我的风格是用 let 和 条件从句 少写代码。不知道算不算坏事。)

1 个赞

spacemacs 自带了透明度设置 SPC-T-T

1 个赞

。。。抓到一个看帖不认真的同学。(滑稽)

先不说这里还有一些没有用 Spacemacs 的。 然后我的关注点是在于 Spacemacs 没有的两个函数。

设置 Emacs 窗口透明:

(set-frame-parameter nil 'alpha '(85 . 100))

其中 85 指定当 Emacs 在使用中时的透明度,而 100 则指定其它应用在使用中时 Emacs 的透明度。

取消透明效果(数字 100 表示不透明):

(set-frame-parameter nil 'alpha '(100 . 100))

(set-frame-parameter nil 'alpha 100)

N(N . N) 的效果相同。

顺便写了一个简单的命令来切换透明与否:

(defun chunyang-toggle-frame-transparency ()
  (interactive)
  (if (equal (frame-parameter nil 'alpha) 85)
      (set-frame-parameter nil 'alpha 100)
    (set-frame-parameter nil 'alpha 85)))

GNU Emacs 26.0.50 (build 5, x86_64-apple-darwin16.5.0, NS appkit-1504.82 Version 10.12.4 (Build 16E195)) of 2017-05-14

2 个赞

虽然 用 (85 100) 也可以,但是最好用 (85 . 100) ,这样可以分别改。

1 个赞

一开始我以为 alpha 的值是个数字,后来我看了上面的几个帖子中的代码

发现也可以是个 List。刚才我看下文档 (elisp) Font and Color Parameters

‘alpha’
     This parameter specifies the opacity of the frame, on graphical
     displays that support variable opacity.  It should be an integer
     between 0 and 100, where 0 means completely transparent and 100
     means completely opaque.  It can also have a ‘nil’ value, which
     tells Emacs not to set the frame opacity (leaving it to the window
     manager).

     The ‘alpha’ frame parameter can also be a cons cell ‘(ACTIVE .
     INACTIVE)’, where ACTIVE is the opacity of the frame when it is
     selected, and INACTIVE is the opacity when it is not selected.

发现它可以是 nil 或数字或 Cons Cell。

安装文档的说明,的确应该用 Cons Cell。但是我没有发现实际的区别,"可以分别改"是什么意思?

我的意思是方便单独修改不活跃窗口和活动窗口的位置 alpha。现在看起来我上面的例子写的有点蹩脚了,明明用setf可以把代码写的更 terse 一点。

虽然用 list 也可以,我也是看了上面提到的 Spacemacs 自带的实现才意识到用 cons cell 才是比较正常的办法。

这跟用 (list 85 100) 还是 (cons 85 100) 有关系吗?

1 个赞
;; 举个栗子
;; for a cons cell `alpha' 
(setf (cdr alpha) 90)
;; for a list `alpha'
(setf (second alpha) 90)

我相信前者肯定更有效率那么一点点。虽然对这一点点效率吹毛求疵有点奇怪。

哦,有点明白你的意思了,但是如果是我的话,直接构造一个新的值传入就完了

(set-frame-parameter nil 'alpha '(85 . 100))

(let ((alpha (frame-parameter nil 'alpha)))
  (set-frame-parameter nil 'alpha (cons (car alpha) 85)))

setf 做同样的事情并不会更容易

(let ((alpha (frame-parameter nil 'alpha)))
  (setf (cdr alpha) 85
        (frame-parameter nil 'alpha) alpha))

但假设 setf 支持这么用就另说了(目前不支持)

(setf (cdr (frame-parameter nil 'alpha)) 85)
3 个赞

kde表示自帶所有窗口獨立透明度調節, 非常方便QAQ

1 个赞

赞!用上了,i3上有了强烈的透明背景需求,就搜到了你的这个帖子 08

有个疑问,这个透明是整个窗口的, 不像alacritty透明度只是背景透明, 但是文字不透明,emacs该如何做到?

Seems not possible :frowning_face:

2 个赞