unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Detecting changes between dark and light mode on Mac OS
@ 2021-03-09 13:23 Daphne Preston-Kendal
  2021-03-20 16:51 ` Daphne Preston-Kendal
  0 siblings, 1 reply; 12+ messages in thread
From: Daphne Preston-Kendal @ 2021-03-09 13:23 UTC (permalink / raw)
  To: emacs-devel

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

Hello,

I've attempted to implement support for detecting and responding to
changes between system dark and light mode on Mac OS.

This patch makes it so that the ns-appearance parameter of a frame is
always bound — if it isn't set by the user, it's set to 'dark or
'light depending on the operating system's default setting. It also
listens for changes in the systemwide appearance, changes the
ns-appearance on all frames when that happens, and runs a new hook,
ns-dark-mode-change-hook. (It's still possible to set ns-appearance on
a frame-by-frame basis, but such changes will be overridden the next
time the systemwide appearance changes.)

This enables users to automatically set Emacs to change their theme
when the system changes from dark to light, for example. (Since
Mac OS 10.15, there is a mode in the system which automatically
changes to dark mode in the evening and light mode during the day;
various third-party utilities existed to provide similar behaviour
before 10.15. So this helps Emacs follow that automatic change,
for example.)

This is my first Emacs patch, and also the first time I've written
Objective-C in probably ten years. So there are probably still
gremlins lurking here and there, and I'd appreciate feedback!

Many thanks


Daphne Preston-Kendal


[-- Attachment #2: 0001-auto-detection-of-ns-appearance-and-an-ns-dark-mode-.patch --]
[-- Type: application/octet-stream, Size: 4845 bytes --]

From 813b66cff906bc39b7615b7ca71689da3388029c 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-detection of ns-appearance, and an
 ns-dark-mode-change-hook

---
 src/nsfns.m  | 10 +++++++++-
 src/nsterm.m | 50 +++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 58 insertions(+), 2 deletions(-)

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..e0632e347e 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,32 @@ - (void)antialiasThresholdDidChange:(NSNotification *)notification
 #endif
 }
 
+- (void)darkModeDidChange:(NSNotification *)notification
+{
+#ifdef NS_IMPL_COCOA
+  NSTRACE ("[EmacsApp darkModeDidChange:]");
+
+  Lisp_Object new_value = [[[self effectiveAppearance]
+                             bestMatchFromAppearancesWithNames:@[
+                                                                 NSAppearanceNameAqua,
+                                                                 NSAppearanceNameDarkAqua
+                                                                 ]
+                            ] isEqualToString:NSAppearanceNameDarkAqua] ? Qlight : Qdark; /* this is backwards; i have no idea why */
+
+  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:
@@ -9790,7 +9833,7 @@ - (CGContextRef) getContext
   IOSurfaceRef surface = NULL;
 
   NSTRACE ("[EmacsSurface getContextWithSize:]");
-  NSTRACE_MSG (@"IOSurface count: %lu", [cache count] + (lastSurface ? 1 : 0));
+  // NSTRACE_MSG (@"IOSurface count: %lu", [cache count] + (lastSurface ? 1 : 0));
 
   for (id object in cache)
     {
@@ -10199,6 +10242,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)


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

end of thread, other threads:[~2021-03-28  1:16 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-09 13:23 Detecting changes between dark and light mode on Mac OS Daphne Preston-Kendal
2021-03-20 16:51 ` Daphne Preston-Kendal
2021-03-20 17:52   ` Alan Third
2021-03-21 11:01     ` Daphne Preston-Kendal
2021-03-21  7:01   ` Lars Ingebrigtsen
2021-03-21 10:22     ` Daphne Preston-Kendal
2021-03-22 20:07       ` Lars Ingebrigtsen
2021-03-23 18:32         ` chad
2021-03-23 17:49     ` Matt Armstrong
2021-03-24  8:30       ` Lars Ingebrigtsen
2021-03-25 16:33         ` Stefan Monnier
2021-03-28  1:16           ` chad

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