doomemacs icon indicating copy to clipboard operation
doomemacs copied to clipboard

Support for dark/light theme switching (match OS preference, e.g. under macOS)

Open rollcat opened this issue 2 years ago • 12 comments

Describe your request

macOS allows the user to specify a preference for a dark or light UI theme, with apps adapting both UI elements and (in some cases) their content presentation to match the user preference. E.g. browsers forward the preference to websites via the prefers-color-scheme CSS media query; editors switch syntax highlighting themes; etc.

The feature could be implemented by asking the user to define their preferred light and dark mode themes, with sensible defaults, e.g. instead of (or in addition to) (setq doom-theme ...), the user could specify (setq doom-theme-dark 'modus-vivendi doom-theme-light 'modus-operandi).

In my current personal config (I'm in the process of giving Doom Emacs a try), I have the following snippet:

(setq system-is-mac (equal 'darwin system-type))
(defun get-appearance-preferences ()
  (if system-is-mac
      (do-applescript "
tell application \"System Events\"
  tell appearance preferences
    if (dark mode) then
      return dark
    else
      return light
    end if
  end tell
end tell
")
     "dark")

This is accompanied by https://github.com/cormacrelf/dark-notify and a shell script that is running in the background (installed manually in system preferences / users / login items):

#!/bin/sh
set -eu
# brew install cormacrelf/tap/dark-notify
export PATH=/opt/homebrew/bin:/usr/local/bin:$PATH
exec dark-notify -c "emacsclient -e '(update-theme)'"

The function update-theme polls get-appearance-preferences and selects the preferred theme.

Of course it would be wonderful if this scheme was OS-independent (I'm also an OpenBSD user, but I'm not sure what's the standard method for specifying dark/light preference), and if it required less manual setup on macOS (although that's probably something that Emacs itself should address).

Briefly explain its use-case

The user can specify the variables doom-theme-dark and doom-theme-light (with sane defaults), and Emacs automatically chooses the theme based on these preferences, and the current system setting. Ideally, Emacs switches between light/dark mode whenever the rest of the system does.

rollcat avatar May 28 '22 11:05 rollcat

emacs-plus already has this.

Any other OS except windows it's a pot luck if a user has a way to specify dark/light preference (GNOME is currently the outlier)

elken avatar May 28 '22 11:05 elken

there is https://github.com/LionyxML/auto-dark-emacs which should work on linux- it says it only supports gnome, but it registers a dbus listener for the org.freedesktop.appearance.color-scheme settings key, which is a standard on linux that already has quite decent support I believe- KDE plasma, gnome and the elementary OS desktop at least should work.

I'll try this out ^^

NANASHI0X74 avatar May 31 '23 10:05 NANASHI0X74

If you're not using a full Desktop Environment, you can use darkman to automatically switch various programs between light and dark mode, and there's darkman.el to sync the Emacs theme.

zeorin avatar Aug 24 '23 22:08 zeorin

there is https://github.com/LionyxML/auto-dark-emacs which should work on linux- it says it only supports gnome, but it registers a dbus listener for the org.freedesktop.appearance.color-scheme settings key, which is a standard on linux that already has quite decent support I believe- KDE plasma, gnome and the elementary OS desktop at least should work.

I'll try this out ^^

Works without issues on Fedora 39.

luisgerhorst avatar Dec 17 '23 11:12 luisgerhorst

So I added

(use-package! auto-dark
  :after doom-themes
  :config (auto-dark-mode t)
  (setq auto-dark-dark-theme 'doom-one)
  (setq auto-dark-light-theme 'doom-one-light))

to my config and it works, but there is an issue on startup- it seems to load two themes somehow, which affects for example the color of the line numbers to the left of the buffer.

If I start emacs in light mode, I have doom-one, leuven in custom-enabled-themes and in dark mode it's doom-one, wombat. I haven't found a way to fix this yet. When I switch themes while emacs is running it works as expected.

NANASHI0X74 avatar Dec 19 '23 08:12 NANASHI0X74

@NANASHI0X74 You need doom-ui instead of doom-themes as of doom v2023-12-08, I already updated the example upstream: https://github.com/LionyxML/auto-dark-emacs/pull/40 - With that custom-enabled-themes only has one theme as value for me (both after startup and switching).

Not sure how leuven/wombat could get in there for you. Changing to doom-ui will likely mask that issue because auto-dark-mode will overwrite it. But still maybe make sure this is not from some other config? (I.e., start doom with the default config and see if the issue persists.)

luisgerhorst avatar Dec 19 '23 09:12 luisgerhorst

wombat and leuven are the defaultd auto-dark-emacs uses, I suspect that's why they get in there

Sláinte, Rian Lindenberger

On Tue, 19 Dec 2023, 10:12 Luis Gerhorst, @.***> wrote:

@NANASHI0X74 https://github.com/NANASHI0X74 You need doom-ui instead of doom-themes as of doom v2023-12-08, I already updated the example upstream: LionyxML/auto-dark-emacs#40 https://github.com/LionyxML/auto-dark-emacs/pull/40 - With that custom-enabled-themes only has one theme as value for me (both after startup and switching).

Not sure how leuven/wombat could get in there for you. Changing to doom-ui will likely mask that issue because auto-dark-mode will overwrite it. But still maybe make sure this is not from some other config? (I.e., start doom with the default config and see if the issue persists.)

— Reply to this email directly, view it on GitHub https://github.com/doomemacs/doomemacs/issues/6424#issuecomment-1862384198, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEF3ZHURRHE64U377K33ZZTYKFK6HAVCNFSM5XGQQXU2U5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCOBWGIZTQNBRHE4A . You are receiving this because you were mentioned.Message ID: @.***>

NANASHI0X74 avatar Dec 19 '23 09:12 NANASHI0X74

Makes sense. I just realized you have to set the variables before activating the mode. Otherwise they are not in effect until the code runs again.

luisgerhorst avatar Dec 19 '23 09:12 luisgerhorst

I recommend using emacs-plus on Mac, which automatically change theme with the system.

yonghuier avatar Dec 19 '23 09:12 yonghuier

@yonghuier

I recommend using emacs-plus on Mac, which automatically change theme with the system.

I use emacs-plus, and I was previously on Spacemacs where I was able to get said hook to work; but on DOOM I just can't seem to manage it. I've put the add-hook in config.el, in init.el, in Emacs' init.el, I've used load-theme, setq doom-theme, every alternative I can imagine; and yet, it simply does not register. Where do I put it and how do I do it to get it to actually work?

DEAR PEOPLE FROM THE FUTURE: I don't fully understand what the problem was, but either one of letf! or setq doom-theme made it not work. The config.el snippet that finally got it working for me uses only standard elisp:

(progn
  (defun lighting (mood)
    (pcase mood
      ('light (load-theme 'doom-one-light t))
      ('dark (load-theme 'doom-one t))))
  (add-hook 'ns-system-appearance-change-functions #'lighting))

If anyone knows what the heck is going on there that'd be great. I'd like to know which of me or DOOM is dumber.

ghost avatar May 15 '24 22:05 ghost

Try putting auto-dark-mode on the doom-init-ui-hook instead. (after! doom-ui ...) is the same as having no after! block at all, since there's no scenario where doom-ui isn't already loaded by that point. E.g.

(use-package! auto-dark
  :hook (doom-init-ui . auto-dark-mode)
  :config 
  (setq auto-dark-dark-theme 'doom-one)
  (setq auto-dark-light-theme 'doom-one-light))

hlissner avatar Sep 09 '24 22:09 hlissner

Fwiw, this works well in my config:

(use-package! auto-dark
  :defer t
  :init
  (setq! auto-dark-dark-theme  'doom-solarized-dark
         auto-dark-light-theme 'doom-solarized-light)
  ;; Inspired by doom-ui.el.
  ;; Note that server-after-make-frame-hook also avoids the issues with an early
  ;; start of the emacs daemon using systemd, which causes problems with the
  ;; DBus connection that auto-dark mode relies upon.
  (let ((hook (if (daemonp)
               'server-after-make-frame-hook
               'after-init-hook)))
    ;; Depth -95 puts this before doom-init-theme-h, which sounds like a good
    ;; idea, if only for performance reasons.
    (add-hook hook #'auto-dark-mode -95)))

real-or-random avatar Sep 13 '24 02:09 real-or-random