emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

night-mode?


From: Stefan Monnier
Subject: night-mode?
Date: Fri, 20 Nov 2020 16:25:35 -0500
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux)

Based on previous discussions, I think we should add some way to toggle
the dark/light mode.  I'm not completely sure what the interface should
look like, nor what'd be the better implementation, but see the patch
below for a first cut to add a `night-mode` command, which does
basically the "inverse video" by swapping the foreground and the
background of the default face (and then resetting the background-mode
accordingly, of course).


        Stefan


Along the way I saw a few other issues:

- `frame-set-background-mode` currently doesn't use `color-dark-p`, and
  the code it uses for that uses a different algorithm, AFAICT.

- The only current use of `color-dark-p`, as well as the potential new
  use of it in `frame-set-background-mode` both have an RGB in form
  [0,65535] and need to scale it to p0,1] before calling `color-dark-p`,
  so maybe `color-dark-p` should be changed to accept colors using the
  [0,65535] scale.


diff --git a/lisp/faces.el b/lisp/faces.el
index 7355e1dd0a..a417979547 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -1798,6 +1798,9 @@ color-luminance-dark-limit
 This value was determined experimentally.")
 
 (defun color-dark-p (rgb)
+  ;; FIXME: The only 2 uses of this function I can find both need to
+  ;; (mapcar (lambda (c) (/ c 65535.0)) because they have RGB on
+  ;; [0,65535] instead of [0,1]!
   "Whether RGB is more readable against white than black.
 RGB is a 3-element list (R G B), each component in the range [0,1].
 This predicate can be used both for determining a suitable (black or white)
diff --git a/lisp/frame.el b/lisp/frame.el
index 772ba3d8c4..57ffb8bee9 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -1159,8 +1159,8 @@ frame-background-mode
   :group 'faces
   :set #'(lambda (var value)
           (set-default var value)
-          (mapc 'frame-set-background-mode (frame-list)))
-  :initialize 'custom-initialize-changed
+          (mapc #'frame-set-background-mode (frame-list)))
+  :initialize #'custom-initialize-changed
   :type '(choice (const dark)
                 (const light)
                 (const :tag "automatic" nil)))
@@ -1173,6 +1173,27 @@ frame-background-mode
 
 (defvar inhibit-frame-set-background-mode nil)
 
+(defun frame--current-backround-mode (frame)
+  (let* ((frame-default-bg-mode (frame-terminal-default-bg-mode frame))
+         (bg-color (frame-parameter frame 'background-color))
+         (tty-type (tty-type frame))
+         (default-bg-mode
+          (if (or (window-system frame)
+                  (and tty-type
+                       (string-match "^\\(xterm\\|rxvt\\|dtterm\\|eterm\\)"
+                                     tty-type)))
+              'light
+            'dark)))
+    (cond (frame-default-bg-mode)
+         ((equal bg-color "unspecified-fg") ; inverted colors
+          (if (eq default-bg-mode 'light) 'dark 'light))
+         ((not (color-values bg-color frame))
+          default-bg-mode)
+         ((color-dark-p (mapcar (lambda (c) (/ c 65535.0))
+                                (color-values bg-color frame)))
+          'dark)
+         (t 'light))))
+
 (defun frame-set-background-mode (frame &optional keep-face-specs)
   "Set up display-dependent faces on FRAME.
 Display-dependent faces are those which have different definitions
@@ -1181,30 +1202,8 @@ frame-set-background-mode
 If optional arg KEEP-FACE-SPECS is non-nil, don't recalculate
 face specs for the new background mode."
   (unless inhibit-frame-set-background-mode
-    (let* ((frame-default-bg-mode (frame-terminal-default-bg-mode frame))
-          (bg-color (frame-parameter frame 'background-color))
-          (tty-type (tty-type frame))
-          (default-bg-mode
-            (if (or (window-system frame)
-                    (and tty-type
-                         (string-match "^\\(xterm\\|rxvt\\|dtterm\\|eterm\\)"
-                                       tty-type)))
-                'light
-              'dark))
-          (non-default-bg-mode (if (eq default-bg-mode 'light) 'dark 'light))
-          (bg-mode
-           (cond (frame-default-bg-mode)
-                 ((equal bg-color "unspecified-fg") ; inverted colors
-                  non-default-bg-mode)
-                 ((not (color-values bg-color frame))
-                  default-bg-mode)
-                 ((>= (apply '+ (color-values bg-color frame))
-                      ;; Just looking at the screen, colors whose
-                      ;; values add up to .6 of the white total
-                      ;; still look dark to me.
-                      (* (apply '+ (color-values "white" frame)) .6))
-                  'light)
-                 (t 'dark)))
+    (let* ((bg-mode
+           (frame--current-backround-mode frame))
           (display-type
            (cond ((null (window-system frame))
                   (if (tty-display-color-p frame) 'color 'mono))
@@ -1270,6 +1269,18 @@ frame-terminal-default-bg-mode
            (intern (downcase bg-resource))))
       (terminal-parameter frame 'background-mode)))
 
+(define-minor-mode night-mode
+  "Use light text on dark background."
+  :global t
+  ;; FIXME: The code below is partly per-frame and partly all-frames :-(
+  (when (eq night-mode
+            (eq 'light (frame--current-backround-mode (selected-frame))))
+    ;; FIXME: Change the face's SPEC instead?
+    (set-face-attribute 'default nil
+                        :foreground (face-attribute 'default :background)
+                        :background (face-attribute 'default :foreground))
+    (frame-set-background-mode (selected-frame))))
+
 
 ;;;; Frame configurations
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]