From 3c1fa68460a0a58f0fbbacd0a08d755d24a4b5ef Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Thu, 4 Feb 2021 19:07:34 +1000 Subject: [PATCH] turn top bar dark when night mode enabled on macOS --- .bazelrc | 3 +++ qt/aqt/data/BUILD.bazel | 1 + qt/aqt/data/lib/BUILD.bazel | 17 +++++++++++++++++ qt/aqt/platform.py | 28 ++++++++++++++++++++++++++++ qt/aqt/theme.py | 10 +++++++++- qt/mac/AnkiHelper.m | 16 ++++++++++++++++ qt/mac/BUILD.bazel | 19 +++++++++++++++++++ qt/mac/README.md | 1 + 8 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 qt/aqt/data/lib/BUILD.bazel create mode 100644 qt/aqt/platform.py create mode 100644 qt/mac/AnkiHelper.m create mode 100644 qt/mac/BUILD.bazel create mode 100644 qt/mac/README.md diff --git a/.bazelrc b/.bazelrc index ed7c1cde2..50b636c49 100644 --- a/.bazelrc +++ b/.bazelrc @@ -5,6 +5,9 @@ common --experimental_repository_cache_hardlinks build:windows --action_env="PYTHON_SYS_EXECUTABLE=c:/python/python.exe" #build:linux --action_env="PYTHON_SYS_EXECUTABLE=/usr/local/bin/python3.8" +# only affects the ankihelper library +#build:macos --macos_cpus=x86_64,arm64 + # runfiles are off by default on Windows, and we need them build --enable_runfiles diff --git a/qt/aqt/data/BUILD.bazel b/qt/aqt/data/BUILD.bazel index 98324bb90..efd53c8ca 100644 --- a/qt/aqt/data/BUILD.bazel +++ b/qt/aqt/data/BUILD.bazel @@ -1,6 +1,7 @@ filegroup( name = "data", srcs = [ + "//qt/aqt/data/lib", "//qt/aqt/data/web", ], visibility = ["//qt:__subpackages__"], diff --git a/qt/aqt/data/lib/BUILD.bazel b/qt/aqt/data/lib/BUILD.bazel new file mode 100644 index 000000000..aa75876fa --- /dev/null +++ b/qt/aqt/data/lib/BUILD.bazel @@ -0,0 +1,17 @@ +load("@bazel_skylib//rules:copy_file.bzl", "copy_file") + +copy_file( + name = "ankihelper_dylib", + src = "//qt/mac:helper_dylib", + out = "libankihelper.dylib", + tags = ["manual"], +) + +filegroup( + name = "lib", + srcs = [] + select({ + "//platforms:macos_x86_64": ["libankihelper.dylib"], + "//conditions:default": [], + }), + visibility = ["//qt:__subpackages__"], +) diff --git a/qt/aqt/platform.py b/qt/aqt/platform.py new file mode 100644 index 000000000..4354eade2 --- /dev/null +++ b/qt/aqt/platform.py @@ -0,0 +1,28 @@ +# Copyright: Ankitects Pty Ltd and contributors +# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +"""Platform-specific functionality.""" + +import os +from ctypes import CDLL + +import aqt.utils +from anki.utils import isMac + + +def set_dark_mode(enabled: bool) -> bool: + "True if setting successful." + if not isMac: + return False + try: + _set_dark_mode(enabled) + return True + except Exception as e: + # swallow exceptions, as library will fail on macOS 10.13 + print(e) + return False + + +def _set_dark_mode(enabled: bool) -> None: + path = os.path.join(aqt.utils.aqt_data_folder(), "lib", "libankihelper.dylib") + CDLL(path).set_darkmode_enabled(enabled) diff --git a/qt/aqt/theme.py b/qt/aqt/theme.py index 8fa2359fc..2741bccb0 100644 --- a/qt/aqt/theme.py +++ b/qt/aqt/theme.py @@ -8,6 +8,7 @@ from typing import Dict, Optional from anki.utils import isMac from aqt import QApplication, gui_hooks, isWin from aqt.colors import colors +from aqt.platform import set_dark_mode from aqt.qt import QColor, QIcon, QPalette, QPixmap, QStyleFactory, Qt @@ -16,15 +17,22 @@ class ThemeManager: _icon_cache_light: Dict[str, QIcon] = {} _icon_cache_dark: Dict[str, QIcon] = {} _icon_size = 128 + _dark_mode_available: Optional[bool] = None def macos_dark_mode(self) -> bool: "True if the user has night mode on, and has forced native widgets." if not isMac: return False + if not self._night_mode_preference: + return False + + if self._dark_mode_available is None: + self._dark_mode_available = set_dark_mode(True) + from aqt import mw - return self._night_mode_preference and mw.pm.dark_mode_widgets() + return self._dark_mode_available and mw.pm.dark_mode_widgets() def get_night_mode(self) -> bool: return self._night_mode_preference diff --git a/qt/mac/AnkiHelper.m b/qt/mac/AnkiHelper.m new file mode 100644 index 000000000..b0bda45e1 --- /dev/null +++ b/qt/mac/AnkiHelper.m @@ -0,0 +1,16 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +@import Foundation; +@import AppKit; + +void set_darkmode_enabled(BOOL enabled) { + NSAppearance *appearance; + if (enabled) { + appearance = [NSAppearance appearanceNamed:NSAppearanceNameDarkAqua]; + } else { + appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua]; + } + + [NSApplication sharedApplication].appearance = appearance; +} diff --git a/qt/mac/BUILD.bazel b/qt/mac/BUILD.bazel new file mode 100644 index 000000000..fc5fcd7ee --- /dev/null +++ b/qt/mac/BUILD.bazel @@ -0,0 +1,19 @@ +load("@rules_cc//cc:defs.bzl", "objc_library") + +objc_library( + name = "helper_static", + srcs = ["AnkiHelper.m"], + enable_modules = True, + alwayslink = True, + sdk_frameworks = ["AppKit"], + tags = ["manual"], +) + +apple_binary( + name = "helper_dylib", + binary_type = "dylib", + minimum_os_version = "10.14", + platform_type = "macos", + visibility = ["//qt:__subpackages__"], + deps = ["helper_static"], +) diff --git a/qt/mac/README.md b/qt/mac/README.md new file mode 100644 index 000000000..eda236ff6 --- /dev/null +++ b/qt/mac/README.md @@ -0,0 +1 @@ +Tiny helper library to set dark mode on and off on Macs.