From 7baa50eca28ff21497b058fa22656bbb4a447d87 Mon Sep 17 00:00:00 2001 From: Alan Third Date: Sun, 20 Aug 2017 21:14:47 +0100 Subject: [PATCH] Add ability to change macOS WM theme (bug#27973) * src/frame.c (make_frame, frame_parms, syms_of_frame) [NS_IMPL_COCOA]: Add ns-appearance and ns-transparent-titlebar options. * src/frame.h (ns_appearance_type) [NS_IMPL_COCOA]: Add enum to represent NSAppearance options. (struct frame) [NS_IMPL_COCOA]: Add ns_appearance and ns_transparent_titlebar frame parameters. * src/nsfns.m (ns_frame_parm_handlers) [NS_IMPL_COCOA]: Add ns_set_appearance and ns_set_transparent_titlebar handlers. (Sx_create_frame): Handle ns-appearance and ns-transparent-titlebar frame parameters. (Qdark): Add new symbol for use with ns-appearance. * src/nsterm.h (ns_set_appearance, ns_set_transparent_titlebar) [NS_IMPL_COCOA]: Add prototypes. * src/nsterm.m (ns_set_appearance, ns_set_transparent_titlebar) [NS_IMPL_COCOA]: New functions. (initFrameFromEmacs) [NS_IMPL_COCOA]: Handle ns-appearance and ns-transparent-titlebar frame parameters. * doc/lispref/frames.texi (Window Management Parameters): Document ns-apperance and ns-transparent-titlebar. --- doc/lispref/frames.texi | 14 +++++++++ src/frame.c | 12 ++++++++ src/frame.h | 18 +++++++++++ src/nsfns.m | 17 +++++++++++ src/nsterm.h | 7 +++++ src/nsterm.m | 68 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 136 insertions(+) diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi index b430f7c6fad..6431bbdedb9 100644 --- a/doc/lispref/frames.texi +++ b/doc/lispref/frames.texi @@ -2125,6 +2125,20 @@ Specifying this lets you create an Emacs window inside some other application's window. (It is not certain this will be implemented; try it and see if it works.) @end ignore + +@vindex ns-appearance, a frame parameter +@item ns-appearance +Only available on macOS, if set to @code{dark} draw this frame's +window-system window using the ``vibrant dark'' theme, otherwise use +the system default. The ``vibrant dark'' theme can be used to set the +toolbar and scrollbars to a dark appearance when using an Emacs theme +with a dark background. + +@vindex ns-transparent-titlebar, a frame parameter +@item ns-transparent-titlebar +Only available on macOS, if non-@code{nil}, set the titlebar and +toolbar to be transparent. This effectively sets the background color +of both to match the Emacs background color. @end table diff --git a/src/frame.c b/src/frame.c index 1e5e4bbdb48..5099f75be4d 100644 --- a/src/frame.c +++ b/src/frame.c @@ -834,6 +834,10 @@ make_frame (bool mini_p) #if ! defined (USE_GTK) && ! defined (HAVE_NS) f->last_tool_bar_item = -1; #endif +#ifdef NS_IMPL_COCOA + f->ns_appearance = ns_appearance_aqua; + f->ns_transparent_titlebar = false; +#endif #endif root_window = make_window (); @@ -3520,6 +3524,10 @@ static const struct frame_parm_table frame_parms[] = {"z-group", SYMBOL_INDEX (Qz_group)}, {"override-redirect", SYMBOL_INDEX (Qoverride_redirect)}, {"no-special-glyphs", SYMBOL_INDEX (Qno_special_glyphs)}, +#ifdef NS_IMPL_COCOA + {"ns-appearance", SYMBOL_INDEX (Qns_appearance)}, + {"ns-transparent-titlebar", SYMBOL_INDEX (Qns_transparent_titlebar)}, +#endif }; #ifdef HAVE_WINDOW_SYSTEM @@ -5646,6 +5654,10 @@ syms_of_frame (void) #ifdef HAVE_NS DEFSYM (Qns_parse_geometry, "ns-parse-geometry"); #endif +#ifdef NS_IMPL_COCOA + DEFSYM (Qns_appearance, "ns-appearance"); + DEFSYM (Qns_transparent_titlebar, "ns-transparent-titlebar"); +#endif DEFSYM (Qalpha, "alpha"); DEFSYM (Qauto_lower, "auto-lower"); diff --git a/src/frame.h b/src/frame.h index 154dc9a3bb4..4b7e448b543 100644 --- a/src/frame.h +++ b/src/frame.h @@ -65,6 +65,14 @@ enum internal_border_part INTERNAL_BORDER_BOTTOM_EDGE, INTERNAL_BORDER_BOTTOM_LEFT_CORNER, }; + +#ifdef NS_IMPL_COCOA +enum ns_appearance_type + { + ns_appearance_aqua, + ns_appearance_vibrant_dark + }; +#endif #endif /* HAVE_WINDOW_SYSTEM */ /* The structure representing a frame. */ @@ -563,6 +571,12 @@ struct frame /* All display backends seem to need these two pixel values. */ unsigned long background_pixel; unsigned long foreground_pixel; + +#ifdef NS_IMPL_COCOA + /* NSAppearance theme used on this frame. */ + enum ns_appearance_type ns_appearance; + bool_bf ns_transparent_titlebar; +#endif }; /* Most code should use these functions to set Lisp fields in struct frame. */ @@ -953,6 +967,10 @@ default_pixels_per_inch_y (void) #define FRAME_Z_GROUP_ABOVE_SUSPENDED(f) \ ((f)->z_group == z_group_above_suspended) #define FRAME_Z_GROUP_BELOW(f) ((f)->z_group == z_group_below) +#ifdef NS_IMPL_COCOA +#define FRAME_NS_APPEARANCE(f) ((f)->ns_appearance) +#define FRAME_NS_TRANSPARENT_TITLEBAR(f) ((f)->ns_transparent_titlebar) +#endif #else /* not HAVE_WINDOW_SYSTEM */ #define FRAME_UNDECORATED(f) ((void) (f), 0) #define FRAME_OVERRIDE_REDIRECT(f) ((void) (f), 0) diff --git a/src/nsfns.m b/src/nsfns.m index e19e4e2641a..b00441eb79f 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -985,6 +985,10 @@ frame_parm_handler ns_frame_parm_handlers[] = x_set_z_group, /* x_set_z_group */ 0, /* x_set_override_redirect */ x_set_no_special_glyphs, +#ifdef NS_IMPL_COCOA + ns_set_appearance, + ns_set_transparent_titlebar, +#endif }; @@ -1277,6 +1281,18 @@ This function is an internal primitive--use `make-frame' instead. */) FRAME_UNDECORATED (f) = !NILP (tem) && !EQ (tem, Qunbound); store_frame_param (f, Qundecorated, FRAME_UNDECORATED (f) ? Qt : Qnil); +#ifdef NS_IMPL_COCOA + tem = x_get_arg (dpyinfo, parms, Qns_appearance, NULL, NULL, RES_TYPE_SYMBOL); + FRAME_NS_APPEARANCE (f) = EQ (tem, Qdark) + ? ns_appearance_vibrant_dark : ns_appearance_aqua; + store_frame_param (f, Qns_appearance, tem); + + tem = x_get_arg (dpyinfo, parms, Qns_transparent_titlebar, + NULL, NULL, RES_TYPE_BOOLEAN); + FRAME_NS_TRANSPARENT_TITLEBAR (f) = !NILP (tem) && !EQ (tem, Qunbound); + store_frame_param (f, Qns_transparent_titlebar, tem); +#endif + parent_frame = x_get_arg (dpyinfo, parms, Qparent_frame, NULL, NULL, RES_TYPE_SYMBOL); /* Accept parent-frame iff parent-id was not specified. */ @@ -3248,6 +3264,7 @@ syms_of_nsfns (void) DEFSYM (Qfontsize, "fontsize"); DEFSYM (Qframe_title_format, "frame-title-format"); DEFSYM (Qicon_title_format, "icon-title-format"); + DEFSYM (Qdark, "dark"); DEFVAR_LISP ("ns-icon-type-alist", Vns_icon_type_alist, doc: /* Alist of elements (REGEXP . IMAGE) for images of icons associated to frames. diff --git a/src/nsterm.h b/src/nsterm.h index 0ac8043e264..65b7a0347ac 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -1210,6 +1210,13 @@ extern void x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value); extern void x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value); +#ifdef NS_IMPL_COCOA +extern void ns_set_appearance (struct frame *f, Lisp_Object new_value, + Lisp_Object old_value); +extern void ns_set_transparent_titlebar (struct frame *f, + Lisp_Object new_value, + Lisp_Object old_value); +#endif extern int ns_select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timespec *timeout, sigset_t *sigmask); diff --git a/src/nsterm.m b/src/nsterm.m index 95092b29c89..22f8efd6b96 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -2036,6 +2036,58 @@ x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) error ("Invalid z-group specification"); } +#ifdef NS_IMPL_COCOA +void +ns_set_appearance (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 + EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); + NSWindow *window = [view window]; + + NSTRACE ("ns_set_appearance"); + +#ifndef NSAppKitVersionNumber10_9 +#define NSAppKitVersionNumber10_9 1265 +#endif + + if (NSAppKitVersionNumber < NSAppKitVersionNumber10_9) + return; + + if (EQ (new_value, Qdark)) + { + window.appearance = [NSAppearance + appearanceNamed: NSAppearanceNameVibrantDark]; + FRAME_NS_APPEARANCE (f) = ns_appearance_vibrant_dark; + } + else + { + window.appearance = [NSAppearance + appearanceNamed: NSAppearanceNameAqua]; + FRAME_NS_APPEARANCE (f) = ns_appearance_aqua; + } +#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */ +} + +void +ns_set_transparent_titlebar (struct frame *f, Lisp_Object new_value, + Lisp_Object old_value) +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 + EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); + NSWindow *window = [view window]; + + NSTRACE ("ns_set_transparent_titlebar"); + + if ([window respondsToSelector: @selector(titlebarAppearsTransparent)] + && !EQ (new_value, old_value)) + { + window.titlebarAppearsTransparent = !NILP (new_value); + FRAME_NS_TRANSPARENT_TITLEBAR (f) = !NILP (new_value); + } +#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */ +} +#endif /* NS_IMPL_COCOA */ + static void ns_fullscreen_hook (struct frame *f) { @@ -7083,6 +7135,22 @@ not_in_argv (NSString *arg) if (! FRAME_UNDECORATED (f)) [self createToolbar: f]; +#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 +#ifndef NSAppKitVersionNumber10_9 +#define NSAppKitVersionNumber10_9 1265 +#endif + + if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_9 + && FRAME_NS_APPEARANCE (f) != ns_appearance_aqua) + win.appearance = [NSAppearance + appearanceNamed: NSAppearanceNameVibrantDark]; +#endif + +#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 + if ([win respondsToSelector: @selector(titlebarAppearsTransparent)]) + win.titlebarAppearsTransparent = FRAME_NS_TRANSPARENT_TITLEBAR (f); +#endif + tem = f->icon_name; if (!NILP (tem)) [win setMiniwindowTitle: -- 2.39.2