mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Desktop: Deprecate isOSXDarkModeActive() and add isDarkModeActive() for other platforms
This commit is contained in:
parent
ea35602f18
commit
3d282c1078
9 changed files with 433 additions and 28 deletions
|
|
@ -503,11 +503,18 @@ DECLARE_JNI_CLASS (AndroidRect, "android/graphics/Rect")
|
|||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (getIdentifier, "getIdentifier", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I") \
|
||||
METHOD (openRawResourceFd, "openRawResourceFd", "(I)Landroid/content/res/AssetFileDescriptor;")
|
||||
METHOD (openRawResourceFd, "openRawResourceFd", "(I)Landroid/content/res/AssetFileDescriptor;") \
|
||||
METHOD (getConfiguration, "getConfiguration", "()Landroid/content/res/Configuration;")
|
||||
|
||||
DECLARE_JNI_CLASS (AndroidResources, "android/content/res/Resources")
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
FIELD (uiMode, "uiMode", "I") \
|
||||
|
||||
DECLARE_JNI_CLASS (AndroidConfiguration, "android/content/res/Configuration")
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (getHeight, "getHeight", "()I") \
|
||||
METHOD (getWidth, "getWidth", "()I")
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ namespace juce
|
|||
|
||||
Desktop::Desktop()
|
||||
: mouseSources (new MouseInputSource::SourceList()),
|
||||
masterScaleFactor ((float) getDefaultMasterScale())
|
||||
masterScaleFactor ((float) getDefaultMasterScale()),
|
||||
nativeDarkModeChangeDetectorImpl (createNativeDarkModeChangeDetectorImpl())
|
||||
{
|
||||
displays.reset (new Displays (*this));
|
||||
}
|
||||
|
|
@ -198,6 +199,12 @@ void Desktop::handleAsyncUpdate()
|
|||
});
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void Desktop::addDarkModeSettingListener (DarkModeSettingListener* l) { darkModeSettingListeners.add (l); }
|
||||
void Desktop::removeDarkModeSettingListener (DarkModeSettingListener* l) { darkModeSettingListeners.remove (l); }
|
||||
|
||||
void Desktop::darkModeChanged() { darkModeSettingListeners.call ([] (DarkModeSettingListener& l) { l.darkModeSettingChanged(); }); }
|
||||
|
||||
//==============================================================================
|
||||
void Desktop::resetTimer()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -45,6 +45,26 @@ public:
|
|||
virtual void globalFocusChanged (Component* focusedComponent) = 0;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Classes can implement this interface and register themselves with the Desktop class
|
||||
to receive callbacks when the operating system dark mode setting changes. The
|
||||
Desktop::isDarkModeActive() method can then be used to query the current setting.
|
||||
|
||||
@see Desktop::addDarkModeSettingListener, Desktop::removeDarkModeSettingListener,
|
||||
Desktop::isDarkModeActive
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API DarkModeSettingListener
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~DarkModeSettingListener() = default;
|
||||
|
||||
/** Callback to indicate that the dark mode setting has changed. */
|
||||
virtual void darkModeSettingChanged() = 0;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
|
|
@ -135,8 +155,7 @@ public:
|
|||
*/
|
||||
void addGlobalMouseListener (MouseListener* listener);
|
||||
|
||||
/** Unregisters a MouseListener that was added with the addGlobalMouseListener()
|
||||
method.
|
||||
/** Unregisters a MouseListener that was added with addGlobalMouseListener().
|
||||
|
||||
@see addGlobalMouseListener
|
||||
*/
|
||||
|
|
@ -150,13 +169,36 @@ public:
|
|||
*/
|
||||
void addFocusChangeListener (FocusChangeListener* listener);
|
||||
|
||||
/** Unregisters a FocusChangeListener that was added with the addFocusChangeListener()
|
||||
method.
|
||||
/** Unregisters a FocusChangeListener that was added with addFocusChangeListener().
|
||||
|
||||
@see addFocusChangeListener
|
||||
*/
|
||||
void removeFocusChangeListener (FocusChangeListener* listener);
|
||||
|
||||
//==============================================================================
|
||||
/** Registers a DarkModeSettingListener that will receive a callback when the
|
||||
operating system dark mode setting changes. To query whether dark mode is on
|
||||
use the isDarkModeActive() method.
|
||||
|
||||
@see isDarkModeActive, removeDarkModeSettingListener
|
||||
*/
|
||||
void addDarkModeSettingListener (DarkModeSettingListener* listener);
|
||||
|
||||
/** Unregisters a DarkModeSettingListener that was added with addDarkModeSettingListener().
|
||||
|
||||
@see addDarkModeSettingListener
|
||||
*/
|
||||
void removeDarkModeSettingListener (DarkModeSettingListener* listener);
|
||||
|
||||
/** True if the operating system "dark mode" is active.
|
||||
|
||||
To receive a callback when this setting changes implement the DarkModeSettingListener
|
||||
interface and use the addDarkModeSettingListener() to register a listener.
|
||||
|
||||
@see addDarkModeSettingListener, removeDarkModeSettingListener
|
||||
*/
|
||||
bool isDarkModeActive() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Takes a component and makes it full-screen, removing the taskbar, dock, etc.
|
||||
|
||||
|
|
@ -352,9 +394,10 @@ public:
|
|||
/** True if the OS supports semitransparent windows */
|
||||
static bool canUseSemiTransparentWindows() noexcept;
|
||||
|
||||
#if JUCE_MAC
|
||||
/** OSX-specific function to check for the "dark" title-bar and menu mode. */
|
||||
static bool isOSXDarkModeActive();
|
||||
#if JUCE_MAC && ! defined (DOXYGEN)
|
||||
[[deprecated ("This macOS-specific method has been deprecated in favour of the cross-platform "
|
||||
" isDarkModeActive() method.")]]
|
||||
static bool isOSXDarkModeActive() { return Desktop::getInstance().isDarkModeActive(); }
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -376,6 +419,7 @@ private:
|
|||
|
||||
ListenerList<MouseListener> mouseListeners;
|
||||
ListenerList<FocusChangeListener> focusListeners;
|
||||
ListenerList<DarkModeSettingListener> darkModeSettingListeners;
|
||||
|
||||
Array<Component*> desktopComponents;
|
||||
Array<ComponentPeer*> peers;
|
||||
|
|
@ -423,6 +467,14 @@ private:
|
|||
Desktop();
|
||||
~Desktop() override;
|
||||
|
||||
//==============================================================================
|
||||
class NativeDarkModeChangeDetectorImpl;
|
||||
std::unique_ptr<NativeDarkModeChangeDetectorImpl> nativeDarkModeChangeDetectorImpl;
|
||||
|
||||
static std::unique_ptr<NativeDarkModeChangeDetectorImpl> createNativeDarkModeChangeDetectorImpl();
|
||||
void darkModeChanged();
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Desktop)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1236,6 +1236,86 @@ bool Desktop::canUseSemiTransparentWindows() noexcept
|
|||
return true;
|
||||
}
|
||||
|
||||
class Desktop::NativeDarkModeChangeDetectorImpl : public ActivityLifecycleCallbacks
|
||||
{
|
||||
public:
|
||||
NativeDarkModeChangeDetectorImpl()
|
||||
{
|
||||
LocalRef<jobject> appContext (getAppContext());
|
||||
|
||||
if (appContext != nullptr)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
myself = GlobalRef (CreateJavaInterface (this, "android/app/Application$ActivityLifecycleCallbacks"));
|
||||
env->CallVoidMethod (appContext.get(), AndroidApplication.registerActivityLifecycleCallbacks, myself.get());
|
||||
}
|
||||
}
|
||||
|
||||
~NativeDarkModeChangeDetectorImpl() override
|
||||
{
|
||||
LocalRef<jobject> appContext (getAppContext());
|
||||
|
||||
if (appContext != nullptr && myself != nullptr)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
env->CallVoidMethod (appContext.get(),
|
||||
AndroidApplication.unregisterActivityLifecycleCallbacks,
|
||||
myself.get());
|
||||
clear();
|
||||
myself.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool isDarkModeEnabled() const noexcept { return darkModeEnabled; }
|
||||
|
||||
void onActivityStarted (jobject /*activity*/) override
|
||||
{
|
||||
const auto isEnabled = getDarkModeSetting();
|
||||
|
||||
if (darkModeEnabled != isEnabled)
|
||||
{
|
||||
darkModeEnabled = isEnabled;
|
||||
Desktop::getInstance().darkModeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static bool getDarkModeSetting()
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
const LocalRef<jobject> resources (env->CallObjectMethod (getAppContext().get(), AndroidContext.getResources));
|
||||
const LocalRef<jobject> configuration (env->CallObjectMethod (resources, AndroidResources.getConfiguration));
|
||||
|
||||
const auto uiMode = env->GetIntField (configuration, AndroidConfiguration.uiMode);
|
||||
|
||||
return ((uiMode & UI_MODE_NIGHT_MASK) == UI_MODE_NIGHT_YES);
|
||||
}
|
||||
|
||||
static constexpr int UI_MODE_NIGHT_MASK = 0x00000030,
|
||||
UI_MODE_NIGHT_NO = 0x00000010,
|
||||
UI_MODE_NIGHT_UNDEFINED = 0x00000000,
|
||||
UI_MODE_NIGHT_YES = 0x00000020;
|
||||
|
||||
GlobalRef myself;
|
||||
bool darkModeEnabled = getDarkModeSetting();
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeDarkModeChangeDetectorImpl)
|
||||
};
|
||||
|
||||
std::unique_ptr<Desktop::NativeDarkModeChangeDetectorImpl> Desktop::createNativeDarkModeChangeDetectorImpl()
|
||||
{
|
||||
return std::make_unique<NativeDarkModeChangeDetectorImpl>();
|
||||
}
|
||||
|
||||
bool Desktop::isDarkModeActive() const
|
||||
{
|
||||
return nativeDarkModeChangeDetectorImpl->isDarkModeEnabled();
|
||||
}
|
||||
|
||||
double Desktop::getDefaultMasterScale()
|
||||
{
|
||||
return 1.0;
|
||||
|
|
|
|||
|
|
@ -137,6 +137,8 @@ using namespace juce;
|
|||
|
||||
- (BOOL) textView: (UITextView*) textView shouldChangeTextInRange: (NSRange) range replacementText: (NSString*) text;
|
||||
|
||||
- (void) traitCollectionDidChange: (UITraitCollection*) previousTraitCollection;
|
||||
|
||||
- (BOOL) isAccessibilityElement;
|
||||
- (CGRect) accessibilityFrame;
|
||||
- (NSArray*) accessibilityElements;
|
||||
|
|
@ -270,6 +272,11 @@ public:
|
|||
return getMouseTime ([e timestamp]);
|
||||
}
|
||||
|
||||
static NSString* getDarkModeNotificationName()
|
||||
{
|
||||
return @"ViewDarkModeChanged";
|
||||
}
|
||||
|
||||
static MultiTouchMapper<UITouch*> currentTouches;
|
||||
|
||||
private:
|
||||
|
|
@ -296,25 +303,27 @@ private:
|
|||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIViewComponentPeer)
|
||||
};
|
||||
|
||||
static UIViewComponentPeer* getViewPeer (JuceUIViewController* c)
|
||||
{
|
||||
if (JuceUIView* juceView = (JuceUIView*) [c view])
|
||||
return juceView->owner;
|
||||
|
||||
jassertfalse;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void sendScreenBoundsUpdate (JuceUIViewController* c)
|
||||
{
|
||||
JuceUIView* juceView = (JuceUIView*) [c view];
|
||||
|
||||
if (juceView != nil && juceView->owner != nullptr)
|
||||
juceView->owner->updateScreenBounds();
|
||||
if (auto* peer = getViewPeer (c))
|
||||
peer->updateScreenBounds();
|
||||
}
|
||||
|
||||
static bool isKioskModeView (JuceUIViewController* c)
|
||||
{
|
||||
JuceUIView* juceView = (JuceUIView*) [c view];
|
||||
if (auto* peer = getViewPeer (c))
|
||||
return Desktop::getInstance().getKioskModeComponent() == &(peer->getComponent());
|
||||
|
||||
if (juceView == nil || juceView->owner == nullptr)
|
||||
{
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
return Desktop::getInstance().getKioskModeComponent() == &(juceView->owner->getComponent());
|
||||
return false;
|
||||
}
|
||||
|
||||
MultiTouchMapper<UITouch*> UIViewComponentPeer::currentTouches;
|
||||
|
|
@ -544,6 +553,22 @@ MultiTouchMapper<UITouch*> UIViewComponentPeer::currentTouches;
|
|||
nsStringToJuce (text));
|
||||
}
|
||||
|
||||
- (void) traitCollectionDidChange: (UITraitCollection*) previousTraitCollection
|
||||
{
|
||||
[super traitCollectionDidChange: previousTraitCollection];
|
||||
|
||||
#if defined (__IPHONE_12_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_12_0
|
||||
if (@available (iOS 12.0, *))
|
||||
{
|
||||
const auto wasDarkModeActive = ([previousTraitCollection userInterfaceStyle] == UIUserInterfaceStyleDark);
|
||||
|
||||
if (wasDarkModeActive != Desktop::getInstance().isDarkModeActive())
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName: UIViewComponentPeer::getDarkModeNotificationName()
|
||||
object: nil];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (BOOL) isAccessibilityElement
|
||||
{
|
||||
return NO;
|
||||
|
|
|
|||
|
|
@ -678,6 +678,77 @@ bool Desktop::canUseSemiTransparentWindows() noexcept
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Desktop::isDarkModeActive() const
|
||||
{
|
||||
#if defined (__IPHONE_12_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_12_0
|
||||
if (@available (iOS 12.0, *))
|
||||
return [[[UIScreen mainScreen] traitCollection] userInterfaceStyle] == UIUserInterfaceStyleDark;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
class Desktop::NativeDarkModeChangeDetectorImpl
|
||||
{
|
||||
public:
|
||||
NativeDarkModeChangeDetectorImpl()
|
||||
{
|
||||
static DelegateClass delegateClass;
|
||||
|
||||
delegate = [delegateClass.createInstance() init];
|
||||
object_setInstanceVariable (delegate, "owner", this);
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
|
||||
[[NSNotificationCenter defaultCenter] addObserver: delegate
|
||||
selector: @selector (darkModeChanged:)
|
||||
name: UIViewComponentPeer::getDarkModeNotificationName()
|
||||
object: nil];
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
}
|
||||
|
||||
~NativeDarkModeChangeDetectorImpl()
|
||||
{
|
||||
object_setInstanceVariable (delegate, "owner", nullptr);
|
||||
[[NSNotificationCenter defaultCenter] removeObserver: delegate];
|
||||
[delegate release];
|
||||
}
|
||||
|
||||
void darkModeChanged()
|
||||
{
|
||||
Desktop::getInstance().darkModeChanged();
|
||||
}
|
||||
|
||||
private:
|
||||
struct DelegateClass : public ObjCClass<NSObject>
|
||||
{
|
||||
DelegateClass() : ObjCClass<NSObject> ("JUCEDelegate_")
|
||||
{
|
||||
addIvar<NativeDarkModeChangeDetectorImpl*> ("owner");
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
|
||||
addMethod (@selector (darkModeChanged:), darkModeChanged, "v@:@");
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
registerClass();
|
||||
}
|
||||
|
||||
static void darkModeChanged (id self, SEL, NSNotification*)
|
||||
{
|
||||
if (auto* owner = getIvar<NativeDarkModeChangeDetectorImpl*> (self, "owner"))
|
||||
owner->darkModeChanged();
|
||||
}
|
||||
};
|
||||
|
||||
id delegate = nil;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeDarkModeChangeDetectorImpl)
|
||||
};
|
||||
|
||||
std::unique_ptr<Desktop::NativeDarkModeChangeDetectorImpl> Desktop::createNativeDarkModeChangeDetectorImpl()
|
||||
{
|
||||
return std::make_unique<NativeDarkModeChangeDetectorImpl>();
|
||||
}
|
||||
|
||||
Point<float> MouseInputSource::getCurrentRawMousePosition()
|
||||
{
|
||||
return juce_lastMousePos;
|
||||
|
|
|
|||
|
|
@ -534,6 +534,18 @@ bool Desktop::canUseSemiTransparentWindows() noexcept
|
|||
return XWindowSystem::getInstance()->canUseSemiTransparentWindows();
|
||||
}
|
||||
|
||||
bool Desktop::isDarkModeActive() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
class Desktop::NativeDarkModeChangeDetectorImpl { public: NativeDarkModeChangeDetectorImpl() = default; };
|
||||
|
||||
std::unique_ptr<Desktop::NativeDarkModeChangeDetectorImpl> Desktop::createNativeDarkModeChangeDetectorImpl()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool screenSaverAllowed = true;
|
||||
|
||||
void Desktop::setScreenSaverEnabled (bool isEnabled)
|
||||
|
|
|
|||
|
|
@ -430,6 +430,73 @@ Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
|
|||
return upright;
|
||||
}
|
||||
|
||||
bool Desktop::isDarkModeActive() const
|
||||
{
|
||||
return [[[NSUserDefaults standardUserDefaults] stringForKey: nsStringLiteral ("AppleInterfaceStyle")]
|
||||
isEqualToString: nsStringLiteral ("Dark")];
|
||||
}
|
||||
|
||||
class Desktop::NativeDarkModeChangeDetectorImpl
|
||||
{
|
||||
public:
|
||||
NativeDarkModeChangeDetectorImpl()
|
||||
{
|
||||
static DelegateClass delegateClass;
|
||||
|
||||
delegate = [delegateClass.createInstance() init];
|
||||
object_setInstanceVariable (delegate, "owner", this);
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
|
||||
[[NSDistributedNotificationCenter defaultCenter] addObserver: delegate
|
||||
selector: @selector (darkModeChanged:)
|
||||
name: @"AppleInterfaceThemeChangedNotification"
|
||||
object: nil];
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
}
|
||||
|
||||
~NativeDarkModeChangeDetectorImpl()
|
||||
{
|
||||
object_setInstanceVariable (delegate, "owner", nullptr);
|
||||
[[NSDistributedNotificationCenter defaultCenter] removeObserver: delegate];
|
||||
[delegate release];
|
||||
}
|
||||
|
||||
void darkModeChanged()
|
||||
{
|
||||
Desktop::getInstance().darkModeChanged();
|
||||
}
|
||||
|
||||
private:
|
||||
struct DelegateClass : public ObjCClass<NSObject>
|
||||
{
|
||||
DelegateClass() : ObjCClass<NSObject> ("JUCEDelegate_")
|
||||
{
|
||||
addIvar<NativeDarkModeChangeDetectorImpl*> ("owner");
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
|
||||
addMethod (@selector (darkModeChanged:), darkModeChanged, "v@:@");
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
registerClass();
|
||||
}
|
||||
|
||||
static void darkModeChanged (id self, SEL, NSNotification*)
|
||||
{
|
||||
if (auto* owner = getIvar<NativeDarkModeChangeDetectorImpl*> (self, "owner"))
|
||||
owner->darkModeChanged();
|
||||
}
|
||||
};
|
||||
|
||||
id delegate = nil;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeDarkModeChangeDetectorImpl)
|
||||
};
|
||||
|
||||
std::unique_ptr<Desktop::NativeDarkModeChangeDetectorImpl> Desktop::createNativeDarkModeChangeDetectorImpl()
|
||||
{
|
||||
return std::make_unique<NativeDarkModeChangeDetectorImpl>();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class ScreenSaverDefeater : public Timer
|
||||
{
|
||||
|
|
@ -674,10 +741,4 @@ void Process::setDockIconVisible (bool isVisible)
|
|||
ignoreUnused (err);
|
||||
}
|
||||
|
||||
bool Desktop::isOSXDarkModeActive()
|
||||
{
|
||||
return [[[NSUserDefaults standardUserDefaults] stringForKey: nsStringLiteral ("AppleInterfaceStyle")]
|
||||
isEqualToString: nsStringLiteral ("Dark")];
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -712,6 +712,8 @@ static void setWindowZOrder (HWND hwnd, HWND insertAfter)
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
extern RTL_OSVERSIONINFOW getWindowsVersionInfo();
|
||||
|
||||
double Desktop::getDefaultMasterScale()
|
||||
{
|
||||
if (! JUCEApplicationBase::isStandaloneApp() || isPerMonitorDPIAwareProcess())
|
||||
|
|
@ -720,7 +722,95 @@ double Desktop::getDefaultMasterScale()
|
|||
return getGlobalDPI() / USER_DEFAULT_SCREEN_DPI;
|
||||
}
|
||||
|
||||
bool Desktop::canUseSemiTransparentWindows() noexcept { return true; }
|
||||
bool Desktop::canUseSemiTransparentWindows() noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
class Desktop::NativeDarkModeChangeDetectorImpl
|
||||
{
|
||||
public:
|
||||
NativeDarkModeChangeDetectorImpl()
|
||||
{
|
||||
const auto winVer = getWindowsVersionInfo();
|
||||
|
||||
if (winVer.dwMajorVersion >= 10 && winVer.dwBuildNumber >= 17763)
|
||||
{
|
||||
const auto uxtheme = "uxtheme.dll";
|
||||
LoadLibraryA (uxtheme);
|
||||
const auto uxthemeModule = GetModuleHandleA (uxtheme);
|
||||
|
||||
if (uxthemeModule != nullptr)
|
||||
{
|
||||
shouldAppsUseDarkMode = (ShouldAppsUseDarkModeFunc) GetProcAddress (uxthemeModule, MAKEINTRESOURCEA (132));
|
||||
|
||||
if (shouldAppsUseDarkMode != nullptr)
|
||||
darkModeEnabled = shouldAppsUseDarkMode() && ! isHighContrast();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isDarkModeEnabled() const noexcept { return darkModeEnabled; }
|
||||
|
||||
private:
|
||||
static bool isHighContrast()
|
||||
{
|
||||
HIGHCONTRASTW highContrast { 0 };
|
||||
|
||||
if (SystemParametersInfoW (SPI_GETHIGHCONTRAST, sizeof (highContrast), &highContrast, false))
|
||||
return highContrast.dwFlags & HCF_HIGHCONTRASTON;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK callWndProc (int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
auto* params = reinterpret_cast<CWPSTRUCT*> (lParam);
|
||||
|
||||
if (nCode >= 0
|
||||
&& params != nullptr
|
||||
&& params->message == WM_SETTINGCHANGE
|
||||
&& params->lParam != 0
|
||||
&& CompareStringOrdinal (reinterpret_cast<LPWCH> (params->lParam), -1, L"ImmersiveColorSet", -1, true) == CSTR_EQUAL)
|
||||
{
|
||||
Desktop::getInstance().nativeDarkModeChangeDetectorImpl->colourSetChanged();
|
||||
}
|
||||
|
||||
return CallNextHookEx ({}, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
void colourSetChanged()
|
||||
{
|
||||
if (shouldAppsUseDarkMode != nullptr)
|
||||
{
|
||||
const auto wasDarkModeEnabled = std::exchange (darkModeEnabled, shouldAppsUseDarkMode() && ! isHighContrast());
|
||||
|
||||
if (darkModeEnabled != wasDarkModeEnabled)
|
||||
Desktop::getInstance().darkModeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
using ShouldAppsUseDarkModeFunc = bool (WINAPI*)();
|
||||
ShouldAppsUseDarkModeFunc shouldAppsUseDarkMode = nullptr;
|
||||
|
||||
bool darkModeEnabled = false;
|
||||
HHOOK hook { SetWindowsHookEx (WH_CALLWNDPROC,
|
||||
callWndProc,
|
||||
(HINSTANCE) juce::Process::getCurrentModuleInstanceHandle(),
|
||||
GetCurrentThreadId()) };
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeDarkModeChangeDetectorImpl)
|
||||
};
|
||||
|
||||
std::unique_ptr<Desktop::NativeDarkModeChangeDetectorImpl> Desktop::createNativeDarkModeChangeDetectorImpl()
|
||||
{
|
||||
return std::make_unique<NativeDarkModeChangeDetectorImpl>();
|
||||
}
|
||||
|
||||
bool Desktop::isDarkModeActive() const
|
||||
{
|
||||
return nativeDarkModeChangeDetectorImpl->isDarkModeEnabled();
|
||||
}
|
||||
|
||||
Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue