unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#47291: [PATCH] Auto-detect ns-appearance of frames and call a hook when it changes
@ 2021-03-21 10:48 Daphne Preston-Kendal
  2021-03-23 18:05 ` Matt Armstrong
  0 siblings, 1 reply; 6+ messages in thread
From: Daphne Preston-Kendal @ 2021-03-21 10:48 UTC (permalink / raw)
  To: 47291

[-- 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 --]




^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-10-08  8:24 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-21 10:48 bug#47291: [PATCH] Auto-detect ns-appearance of frames and call a hook when it changes Daphne Preston-Kendal
2021-03-23 18:05 ` 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

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).