5

VS Code recently added the ability to switch themes when macOS's dark mode changes. Presumably they use the Electron API, which internally uses the Objective-C API of subscribing to the AppleInterfaceThemeChangedNotification event in NSDistributedNotificationCenter.

It would be nice if Emacs had this same ability. The pseudo-code would be:

(add-event 'os-dark-mode-changed
  (lambda (on)
    (set-theme (if on
                  some-dark-theme
                  some-light-theme))))

(In VS Code, the dark and light themes are configurable.)

Does Emacs have the ability to do something similar?

3
  • Maybe you can periodically query the dark mode status.
    – Juancho
    Commented Feb 11, 2020 at 1:04
  • 1
    Then I'd have to poll, whereas macOS already provides an event for this. There was a reddit thread on this solution and it was generally thought of as being bad practice.
    – user26822
    Commented Feb 11, 2020 at 19:22
  • 2
    I’ve submitted a patch which provides an ns-dark-mode-change-hook which you could use to do this. Hopefully it will be accepted, and then a future version of Emacs will have this feature! Commented Mar 9, 2021 at 15:32

2 Answers 2

2

Using emacs-plus this is easy. See the docs, but here is the code in any case.

(defun my/apply-theme (appearance)
  "Load theme, taking current system APPEARANCE into consideration."
  (mapc #'disable-theme custom-enabled-themes)
  (pcase appearance
    ('light (load-theme 'tango t))
    ('dark (load-theme 'tango-dark t))))

(add-hook 'ns-system-appearance-change-functions #'my/apply-theme)
0

A work-around, more so than an answer: you can change your theme from an external process, by starting your main editor instance in server mode, and using emacsclient. E.g.

(server-start)

And:

emacsclient --eval "(my/dark-mode)" --quiet -no-wait --suppress-output -a true

It turns out that iTerm2 allows you to execute an arbitrary Python script on OS theme changes. You can use this to change iTerm2's own theme, but nothing stops you from adding a cheeky call to emacsclient and controlling Emacs along, with it.

I've combined all of this here: https://gist.github.com/hraban/8eb4ab5c110828a9d1b8c16b4f78193e.

Upside: no polling, no Emacs UI blocking, etc

Downside: iTerm2 must be running.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.