From b4a6c7339d74e8ff83841abf1219e36c3eefeda4 Mon Sep 17 00:00:00 2001 From: Nikita Prokopov Date: Mon, 4 Oct 2021 18:56:46 +0200 Subject: [PATCH] Theme for macOS, PanelTheme #153 #161 --- README.md | 8 +++++++- examples/java/Example.java | 5 ++++- examples/java/PanelTheme.java | 26 ++++++++++++++++++++++++++ macos/cc/ThemeMac.mm | 35 +++++++++++++++++++++++++++++++++++ shared/cc/Theme.hh | 8 -------- shared/java/Theme.java | 24 ++++++++++++++++++------ windows/CMakeLists.txt | 1 - windows/cc/AppWin32.hh | 3 --- windows/cc/ThemeWin32.cc | 26 +++++++++----------------- windows/cc/ThemeWin32.hh | 17 ----------------- 10 files changed, 99 insertions(+), 54 deletions(-) create mode 100644 examples/java/PanelTheme.java create mode 100644 macos/cc/ThemeMac.mm delete mode 100644 shared/cc/Theme.hh delete mode 100644 windows/cc/ThemeWin32.hh diff --git a/README.md b/README.md index ed3b6514..6298072b 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,13 @@ Alpha. Expect API breakages. | runOnUIThread | ✅ | ✅ | [#113](https://github.com/HumbleUI/JWM/issues/113) | | terminate | ✅ | ✅ | ✅ | | Show notification | ❌ | ❌ | ❌ | -| System Theme | ❌ | ❌ | ❌ | + +### Theme +| | Windows | macOS | X11 | +|-------------------|---------|-------|-----| +| isHighContrast | ✅ | ✅ | ➖ | +| isDark | [#161](https://github.com/HumbleUI/JWM/issues/161) | ✅ | ➖ | +| isInvereted | [#161](https://github.com/HumbleUI/JWM/issues/161) | ✅ | ➖ | ### Window diff --git a/examples/java/Example.java b/examples/java/Example.java index 482ee9f6..87c12d10 100644 --- a/examples/java/Example.java +++ b/examples/java/Example.java @@ -26,6 +26,7 @@ public class Example implements Consumer { public PanelMouseCursors panelMouseCursors; public PanelRendering panelRendering; public PanelEvents panelEvents; + public PanelTheme panelTheme; public Window window; @@ -44,6 +45,7 @@ public Example() { panelMouseCursors = new PanelMouseCursors(window); panelRendering = new PanelRendering(window); panelEvents = new PanelEvents(window); + panelTheme = new PanelTheme(window); var scale = window.getScreen().getScale(); int count = App._windows.size() - 1; @@ -112,7 +114,8 @@ public void paint(String reason) { panelRendering.paint (canvas, PADDING + (panelWidth + PADDING) * 2, PADDING + (panelHeight + PADDING) * 1, panelWidth, panelHeight, scale); // Third row - panelEvents.paint (canvas, PADDING + (panelWidth + PADDING) * 0, PADDING + (panelHeight + PADDING) * 2, panelWidth * 3 + PADDING * 2, panelHeight, scale); + panelEvents.paint (canvas, PADDING + (panelWidth + PADDING) * 0, PADDING + (panelHeight + PADDING) * 2, panelWidth * 2 + PADDING, panelHeight, scale); + panelTheme.paint (canvas, PADDING + (panelWidth + PADDING) * 2, PADDING + (panelHeight + PADDING) * 2, panelWidth, panelHeight, scale); // Colored bars try (var paint = new Paint()) { diff --git a/examples/java/PanelTheme.java b/examples/java/PanelTheme.java new file mode 100644 index 00000000..a5047dd8 --- /dev/null +++ b/examples/java/PanelTheme.java @@ -0,0 +1,26 @@ +package io.github.humbleui.jwm.examples; + +import io.github.humbleui.jwm.*; +import org.jetbrains.skija.*; + +public class PanelTheme extends Panel { + + public PanelTheme(Window window) { + super(window); + } + + @Override + public void paintImpl(Canvas canvas, int width, int height, float scale) { + try (var paint = new Paint()) { + paint.setColor(0xFFFFFFFF); + canvas.drawString("isHighContrast", Example.PADDING, Example.PADDING * 2, Example.FONT12, paint); + canvas.drawString("" + Theme.isHighContrast(), width / 2 + Example.PADDING / 2, Example.PADDING * 2, Example.FONT12, paint); + + canvas.drawString("isDark", Example.PADDING, Example.PADDING * 4, Example.FONT12, paint); + canvas.drawString("" + Theme.isDark(), width / 2 + Example.PADDING / 2, Example.PADDING * 4, Example.FONT12, paint); + + canvas.drawString("isInverted", Example.PADDING, Example.PADDING * 6, Example.FONT12, paint); + canvas.drawString("" + Theme.isInverted(), width / 2 + Example.PADDING / 2, Example.PADDING * 6, Example.FONT12, paint); + } + } +} \ No newline at end of file diff --git a/macos/cc/ThemeMac.mm b/macos/cc/ThemeMac.mm new file mode 100644 index 00000000..f2342959 --- /dev/null +++ b/macos/cc/ThemeMac.mm @@ -0,0 +1,35 @@ +#import +#include + +const CFStringRef WhiteOnBlack = CFSTR("whiteOnBlack"); +const CFStringRef UniversalAccessDomain = CFSTR("com.apple.universalaccess"); + +extern "C" JNIEXPORT bool JNICALL Java_io_github_humbleui_jwm_Theme__1nIsHighContrast + (JNIEnv* env, jclass jclass) { + NSWorkspace* workspace = [NSWorkspace sharedWorkspace]; + if ([workspace respondsToSelector:@selector (accessibilityDisplayShouldIncreaseContrast)]) { + return workspace.accessibilityDisplayShouldIncreaseContrast; + } + return false; +} + +extern "C" JNIEXPORT bool JNICALL Java_io_github_humbleui_jwm_Theme__1nIsDark + (JNIEnv* env, jclass jclass) { + if (@available(macOS 10.14, *)) { + NSAppearanceName appearance = [[NSApp effectiveAppearance] bestMatchFromAppearancesWithNames:@[ + NSAppearanceNameAqua, NSAppearanceNameDarkAqua + ]]; + return [appearance isEqual:NSAppearanceNameDarkAqua]; + } + return false; +} + +extern "C" JNIEXPORT bool JNICALL Java_io_github_humbleui_jwm_Theme__1nIsInverted + (JNIEnv* env, jclass jclass) { + CFPreferencesAppSynchronize(UniversalAccessDomain); + Boolean keyExistsAndHasValidFormat = false; + Boolean is_inverted = CFPreferencesGetAppBooleanValue(WhiteOnBlack, UniversalAccessDomain, &keyExistsAndHasValidFormat); + if (!keyExistsAndHasValidFormat) + return false; + return is_inverted; +} diff --git a/shared/cc/Theme.hh b/shared/cc/Theme.hh deleted file mode 100644 index 6c0b2a71..00000000 --- a/shared/cc/Theme.hh +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -namespace jwm { - class Theme { - public: - bool isHighContrast(); - }; -} // namespace jwm diff --git a/shared/java/Theme.java b/shared/java/Theme.java index c6d5852c..f031d273 100644 --- a/shared/java/Theme.java +++ b/shared/java/Theme.java @@ -4,21 +4,33 @@ import io.github.humbleui.jwm.impl.*; public class Theme { - /** - *

>Check whether OS currently uses high contrast mode.

+ *

Check whether OS currently uses high contrast mode.

* - * @return bool; + * @return bool on Windows macOS, false otherwise */ public static boolean isHighContrast() { - assert _onUIThread(); + assert App._onUIThread(); + if (Platform.CURRENT != Platform.WINDOWS && Platform.CURRENT != Platform.MACOS) + return false; return _nIsHighContrast(); } + public static boolean isDark() { + assert App._onUIThread(); + if (Platform.CURRENT != Platform.MACOS) + return false; + return _nIsDark(); + } - @ApiStatus.Internal public static boolean _onUIThread() { - return App._onUIThread(); + public static boolean isInverted() { + assert App._onUIThread(); + if (Platform.CURRENT != Platform.MACOS) + return false; + return _nIsInverted(); } @ApiStatus.Internal public static native boolean _nIsHighContrast(); + @ApiStatus.Internal public static native boolean _nIsDark(); + @ApiStatus.Internal public static native boolean _nIsInverted(); } diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index cda61047..6963fc11 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -46,7 +46,6 @@ set(JWM_WINDOWS_SOURCES_CXX cc/LayerWGL.cc cc/LayerWGL.hh cc/ThemeWin32.cc - cc/ThemeWin32.hh cc/PlatformWin32.hh cc/ScreenWin32.cc cc/ScreenWin32.hh diff --git a/windows/cc/AppWin32.hh b/windows/cc/AppWin32.hh index f678ee59..32824982 100644 --- a/windows/cc/AppWin32.hh +++ b/windows/cc/AppWin32.hh @@ -5,7 +5,6 @@ #include #include #include -#include #include namespace jwm { @@ -26,13 +25,11 @@ namespace jwm { ContextWGL& getContextWGL() { return _wglContext; } DX12Common& getDx12Common() { return _dx12common; } JNIEnv* getJniEnv() const { return _jniEnv; } - ThemeWin32& getTheme() { return _theme; } private: std::vector _screens; WindowManagerWin32 _windowManager; ClipboardWin32 _clipboard; - ThemeWin32 _theme; ContextWGL _wglContext; DX12Common _dx12common; JNIEnv* _jniEnv; diff --git a/windows/cc/ThemeWin32.cc b/windows/cc/ThemeWin32.cc index 73437c03..1b7b77f1 100644 --- a/windows/cc/ThemeWin32.cc +++ b/windows/cc/ThemeWin32.cc @@ -1,5 +1,3 @@ -#include "ThemeWin32.hh" - #include #include #include @@ -8,29 +6,23 @@ #include #include #include -#include "Theme.hh" +using namespace jwm; + +// JNI -bool jwm::ThemeWin32::isHighContrast() { +extern "C" JNIEXPORT bool JNICALL Java_io_github_humbleui_jwm_Theme__1nIsHighContrast + (JNIEnv* env, jclass jclass) { HIGHCONTRASTA highContrast; highContrast.cbSize = sizeof(HIGHCONTRASTA); highContrast.dwFlags = 0; highContrast.lpszDefaultScheme = nullptr; bool isOk = SystemParametersInfoA(SPI_GETHIGHCONTRAST, 0, &highContrast, 0); if (!isOk) { - JWM_VERBOSE("Failed to get SystemParametersInfoA for high contrast"); + JWM_LOG("Failed to get SystemParametersInfoA for high contrast"); return false; } - JWM_VERBOSE("is HighContrast? '" - << ((HCF_HIGHCONTRASTON & highContrast.dwFlags) == 1) << "'"); - return (HCF_HIGHCONTRASTON & highContrast.dwFlags) == 1; -} - -// JNI - -extern "C" JNIEXPORT bool JNICALL Java_io_github_humbleui_jwm_Theme__1nIsHighContrast - (JNIEnv* env, jclass jclass) { - jwm::AppWin32& app = jwm::AppWin32::getInstance(); - jwm::ThemeWin32& theme = app.getTheme(); - return theme.isHighContrast(); + bool result = (HCF_HIGHCONTRASTON & highContrast.dwFlags) == 1; + JWM_VERBOSE("is HighContrast? '" << result << "'"); + return result; } diff --git a/windows/cc/ThemeWin32.hh b/windows/cc/ThemeWin32.hh deleted file mode 100644 index 609746eb..00000000 --- a/windows/cc/ThemeWin32.hh +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include - -#include "Theme.hh" -#include "ThemeWin32.hh" - -namespace jwm { - - class ThemeWin32 final : public Theme { - public: - ThemeWin32() = default; - ~ThemeWin32() = default; - - bool isHighContrast(); - - }; -} // namespace jwm