unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Daphne Preston-Kendal <dpk@nonceword.org>
To: 47291@debbugs.gnu.org
Subject: bug#47291: [PATCH] Auto-detect ns-appearance of frames and call a hook when it changes
Date: Sun, 21 Mar 2021 11:48:10 +0100	[thread overview]
Message-ID: <1B39376A-B108-41FD-87EE-52D68E8F7256@nonceword.org> (raw)

[-- Attachment #1: Type: text/plain, Size: 1119 bytes --]

This is a slightly cleaned-up version of the patch I initially posted for
commentary on emacs-devel.
<https://lists.gnu.org/archive/html/emacs-devel/2021-03/msg00482.html>

The patch makes two closely related changes: when a new frame is
created, the ns-appearance parameter (which was already in Emacs) is
bound to 'light or 'dark depending on the system theme. (Previously,
it could be set explicitly and Emacs would respect that change on a
per-frame basis, but if it wasn't explicitly set it was unbound.)
Secondly, it registers an event handler for changes to the system-wide
theme, and when the system theme changes, it changes the ns-appearance
parameter of all frames to match the new system theme, and runs a new
hook, ns-dark-mode-changed-hook so that users can e.g. set a new Emacs
theme to match the new system theme or whatever.

The patch is against Emacs HEAD as of time of writing. (3cbf92323c)

As mentioned on emacs-devel, this is my first Emacs patch and my first
time programming Objective-C in a long while, so I’d definitely
appreciate feedback!


Daphne Preston-Kendal


[-- Attachment #2: 0001-Auto-detect-ns-appearance-of-frames-and-call-a-hook-.patch --]
[-- Type: application/octet-stream, Size: 5071 bytes --]

From f0fec3e277432d20a38c50685a84448e7cd5a536 Mon Sep 17 00:00:00 2001
From: Daphne Preston-Kendal <git@dpk.io>
Date: Tue, 9 Mar 2021 13:05:13 +0100
Subject: [PATCH] Auto-detect ns-appearance of frames and call a hook when it
 changes.

* src/nsfns.m (Fx_create_frame): Automatically set the ns-appearance
paramter of a frame from the current system appearance on Mac OS.
* src/nsterm.m: Register for system dark/light mode change events on
Mac OS, and update the ns-appearance parameter of frames when the
system theme changes, calling a new ns-dark-mode-changed-hook when
done.
---
 src/nsfns.m  | 10 +++++++++-
 src/nsterm.m | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/src/nsfns.m b/src/nsfns.m
index 5c4cc915e7..fc73725226 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -1284,7 +1284,15 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side.
   else if (EQ (tem, Qlight))
     FRAME_NS_APPEARANCE (f) = ns_appearance_aqua;
   else
-    FRAME_NS_APPEARANCE (f) = ns_appearance_system_default;
+    {
+      tem = [[[NSApp effectiveAppearance]
+               bestMatchFromAppearancesWithNames:@[
+                                                   NSAppearanceNameAqua,
+                                                   NSAppearanceNameDarkAqua
+                                                   ]
+              ] isEqualToString:NSAppearanceNameDarkAqua] ? Qdark : Qlight;
+      FRAME_NS_APPEARANCE (f) = (tem == Qdark ? ns_appearance_vibrant_dark : ns_appearance_aqua);
+    }
   store_frame_param (f, Qns_appearance,
                      (!NILP (tem) && !EQ (tem, Qunbound)) ? tem : Qnil);
 
diff --git a/src/nsterm.m b/src/nsterm.m
index bf175bbd18..2a0213dcb4 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -2207,6 +2207,14 @@ so some key presses (TAB) are swallowed by the system.  */
 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
 }
 
+void
+ns_update_system_appearance (struct frame *f, Lisp_Object new_value)
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
+  store_frame_param (f, Qns_appearance, new_value);
+#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
+}
+
 void
 ns_set_transparent_titlebar (struct frame *f, Lisp_Object new_value,
                              Lisp_Object old_value)
@@ -5926,6 +5934,15 @@ - (void)applicationDidFinishLaunching: (NSNotification *)notification
 	 object:nil];
 #endif
 
+#ifdef NS_IMPL_COCOA
+  [[NSDistributedNotificationCenter defaultCenter]
+    addObserver:self
+       selector:@selector(darkModeDidChange:)
+           name:@"AppleInterfaceThemeChangedNotification"
+         object:nil
+   ];
+#endif
+
 #ifdef NS_IMPL_COCOA
   /* Some functions/methods in CoreFoundation/Foundation increase the
      maximum number of open files for the process in their first call.
@@ -5964,6 +5981,36 @@ - (void)antialiasThresholdDidChange:(NSNotification *)notification
 #endif
 }
 
+- (void)darkModeDidChange:(NSNotification *)notification
+{
+#ifdef NS_IMPL_COCOA
+  NSTRACE ("[EmacsApp darkModeDidChange:]");
+
+  /* It appears that the AppleInterfaceThemeChangedNotification is
+     sent to the app before the effectiveAppearance is set, so
+     if the effectiveAppearance matches the dark theme, we assume
+     the new theme is the light theme, and vice-versa. */
+  Lisp_Object new_value = [[[self effectiveAppearance]
+                             bestMatchFromAppearancesWithNames:@[
+                                                                 NSAppearanceNameAqua,
+                                                                 NSAppearanceNameDarkAqua
+                                                                 ]
+                            ] isEqualToString:NSAppearanceNameDarkAqua] ? Qlight : Qdark;
+
+  Lisp_Object tail, frame;
+  FOR_EACH_FRAME (tail, frame)
+    {
+      struct frame *f = XFRAME (frame);
+      EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
+      EmacsWindow *window = (EmacsWindow *)[view window];
+      ns_update_system_appearance (f, new_value);
+      ns_set_appearance (f, new_value,
+                         (new_value == Qdark ? Qlight : Qdark));
+    }
+
+  run_hook (Qns_dark_mode_changed_hook);
+#endif
+}
 
 /* Termination sequences:
     C-x C-c:
@@ -10199,6 +10246,11 @@ Nil means use fullscreen the old (< 10.7) way.  The old way works better with
 This variable is ignored on Mac OS X < 10.7 and GNUstep.  */);
   ns_use_srgb_colorspace = YES;
 
+  DEFSYM (Qns_dark_mode_changed_hook, "ns-dark-mode-changed-hook");
+
+  DEFVAR_LISP ("ns-dark-mode-changed-hook", Vns_dark_mode_changed_hook,
+               doc: /* Hook run when the Mac OS system-wide UI theme changes from dark to light or vice versa. */);
+
   DEFVAR_BOOL ("ns-use-mwheel-acceleration",
                ns_use_mwheel_acceleration,
      doc: /* Non-nil means use macOS's standard mouse wheel acceleration.
-- 
2.24.3 (Apple Git-128)


[-- Attachment #3: Type: text/plain, Size: 2 bytes --]




             reply	other threads:[~2021-03-21 10:48 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-21 10:48 Daphne Preston-Kendal [this message]
2021-03-23 18:05 ` bug#47291: [PATCH] Auto-detect ns-appearance of frames and call a hook when it changes Matt Armstrong
2021-05-18 14:43   ` Lars Ingebrigtsen
2021-05-18 17:44     ` Alan Third
2021-05-18 18:03   ` Daphne Preston-Kendal
2021-10-08  8:24     ` Daphne Preston-Kendal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1B39376A-B108-41FD-87EE-52D68E8F7256@nonceword.org \
    --to=dpk@nonceword.org \
    --cc=47291@debbugs.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).