Initial commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
# Uncomment these types if you want even more clean repository. But be careful.
|
||||||
|
# It can make harm to an existing project source. Read explanations below.
|
||||||
|
#
|
||||||
|
# Resource files are binaries containing manifest, project icon and version info.
|
||||||
|
# They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files.
|
||||||
|
#*.res
|
||||||
|
#
|
||||||
|
# Type library file (binary). In old Delphi versions it should be stored.
|
||||||
|
# Since Delphi 2009 it is produced from .ridl file and can safely be ignored.
|
||||||
|
#*.tlb
|
||||||
|
#
|
||||||
|
# Diagram Portfolio file. Used by the diagram editor up to Delphi 7.
|
||||||
|
# Uncomment this if you are not using diagrams or use newer Delphi version.
|
||||||
|
#*.ddp
|
||||||
|
#
|
||||||
|
# Visual LiveBindings file. Added in Delphi XE2.
|
||||||
|
# Uncomment this if you are not using LiveBindings Designer.
|
||||||
|
#*.vlb
|
||||||
|
#
|
||||||
|
# Deployment Manager configuration file for your project. Added in Delphi XE2.
|
||||||
|
# Uncomment this if it is not mobile development and you do not use remote debug feature.
|
||||||
|
#*.deployproj
|
||||||
|
#
|
||||||
|
# C++ object files produced when C/C++ Output file generation is configured.
|
||||||
|
# Uncomment this if you are not using external objects (zlib library for example).
|
||||||
|
#*.obj
|
||||||
|
#
|
||||||
|
|
||||||
|
# Delphi compiler-generated binaries (safe to delete)
|
||||||
|
*.exe
|
||||||
|
*.dll
|
||||||
|
*.bpl
|
||||||
|
*.bpi
|
||||||
|
*.dcp
|
||||||
|
*.so
|
||||||
|
*.apk
|
||||||
|
*.drc
|
||||||
|
*.map
|
||||||
|
*.dres
|
||||||
|
*.rsm
|
||||||
|
*.tds
|
||||||
|
*.dcu
|
||||||
|
*.lib
|
||||||
|
*.a
|
||||||
|
*.o
|
||||||
|
*.ocx
|
||||||
|
|
||||||
|
# Delphi autogenerated files (duplicated info)
|
||||||
|
*.cfg
|
||||||
|
*.hpp
|
||||||
|
*Resource.rc
|
||||||
|
|
||||||
|
# Delphi local files (user-specific info)
|
||||||
|
*.local
|
||||||
|
*.identcache
|
||||||
|
*.projdata
|
||||||
|
*.tvsconfig
|
||||||
|
*.dsk
|
||||||
|
|
||||||
|
# Delphi history and backups
|
||||||
|
__history/
|
||||||
|
__recovery/
|
||||||
|
*.~*
|
||||||
|
|
||||||
|
# Castalia statistics file (since XE7 Castalia is distributed with Delphi)
|
||||||
|
*.stat
|
||||||
|
|
||||||
|
# Boss dependency manager vendor folder https://github.com/HashLoad/boss
|
||||||
|
modules/
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
unit DarkModeApi.Consts;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
{$IFDEF MSWINDOWS}
|
||||||
|
|
||||||
|
uses
|
||||||
|
System.UITypes;
|
||||||
|
|
||||||
|
const
|
||||||
|
BackColor: TColor = $1E1E1E;
|
||||||
|
TextColor: TColor = $F0F0F0;
|
||||||
|
InputBackColor: TColor = $303030;
|
||||||
|
Dwmapi = 'DWMAPI.DLL';
|
||||||
|
CDarkModeExplorer = 'DarkMode_Explorer';
|
||||||
|
CModeExplorer = 'Explorer';
|
||||||
|
CDarkModeControlCFD = 'DarkMode_CFD';
|
||||||
|
DWM_CLOAKED_APP = $0000001;
|
||||||
|
DWM_CLOAKED_SHELL = $0000002;
|
||||||
|
DWM_CLOAKED_INHERITED = $0000004;
|
||||||
|
ODS_NOACCEL = $0100;
|
||||||
|
WM_UAHDESTROYWINDOW = $0090; // handled by DefWindowProc
|
||||||
|
WM_UAHDRAWMENU = $0091; // lParam is UAHMENU
|
||||||
|
WM_UAHDRAWMENUITEM = $0092; // lParam is UAHDRAWMENUITEM
|
||||||
|
WM_UAHINITMENU = $0093; // handled by DefWindowProc
|
||||||
|
WM_UAHMEASUREMENUITEM = $0094; // lParam is UAHMEASUREMENUITEM
|
||||||
|
WM_UAHNCPAINTMENUPOPUP = $0095; // handled by DefWindowProc
|
||||||
|
WM_UAHUPDATE = $0096;
|
||||||
|
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
unit DarkModeApi.FMX;
|
||||||
|
|
||||||
|
{$IFDEF MSWINDOWS}
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
FMX.Forms, FMX.Types;
|
||||||
|
|
||||||
|
type
|
||||||
|
TFormHelper = class helper for TForm
|
||||||
|
procedure SetWindowColorModeAsSystem;
|
||||||
|
procedure SetWindowColorMode(IsDark: Boolean);
|
||||||
|
class function SystemIsDarkMode: Boolean;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure SetWindowColorModeAsSystemFor(Handle: TWindowHandle);
|
||||||
|
|
||||||
|
procedure SetWindowColorModeFor(Handle: TWindowHandle; IsDark: Boolean);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
DarkModeApi, FMX.Platform.Win, Winapi.Windows;
|
||||||
|
|
||||||
|
procedure SetWindowColorModeAsSystemFor(Handle: TWindowHandle);
|
||||||
|
var
|
||||||
|
Value: LongBool;
|
||||||
|
WinHandle: HWND;
|
||||||
|
begin
|
||||||
|
Value := IsDarkMode;
|
||||||
|
WinHandle := FmxHandleToHWND(Handle);
|
||||||
|
DwmSetWindowAttribute(WinHandle, ImmersiveDarkMode, Value, SizeOf(Value));
|
||||||
|
AllowDarkModeForWindow(WinHandle, Value);
|
||||||
|
AllowDarkModeForApp(Value);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure SetWindowColorModeFor(Handle: TWindowHandle; IsDark: Boolean);
|
||||||
|
var
|
||||||
|
Value: LongBool;
|
||||||
|
WinHandle: HWND;
|
||||||
|
begin
|
||||||
|
Value := IsDark;
|
||||||
|
WinHandle := FmxHandleToHWND(Handle);
|
||||||
|
DwmSetWindowAttribute(WinHandle, ImmersiveDarkMode, Value, SizeOf(Value));
|
||||||
|
AllowDarkModeForWindow(WinHandle, Value);
|
||||||
|
AllowDarkModeForApp(Value);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TFormHelper }
|
||||||
|
|
||||||
|
procedure TFormHelper.SetWindowColorMode(IsDark: Boolean);
|
||||||
|
begin
|
||||||
|
SetWindowColorModeFor(handle, IsDark);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TFormHelper.SetWindowColorModeAsSystem;
|
||||||
|
begin
|
||||||
|
SetWindowColorModeAsSystemFor(Handle);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TFormHelper.SystemIsDarkMode: Boolean;
|
||||||
|
begin
|
||||||
|
Result := IsDarkMode;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{$ELSE}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
unit DarkModeApi.Types;
|
||||||
|
|
||||||
|
{$IFDEF MSWINDOWS}
|
||||||
|
{$ALIGN ON}
|
||||||
|
{$MINENUMSIZE 4}
|
||||||
|
{$WEAKPACKAGEUNIT}
|
||||||
|
{$WARN SYMBOL_PLATFORM OFF}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Winapi.Windows;
|
||||||
|
|
||||||
|
type
|
||||||
|
TWinRoundType = (wrtDEFAULT = 0, wrtDONOTROUND = 1, wrtROUND = 2, wrtROUNDSMALL = 3);
|
||||||
|
|
||||||
|
TDwmWindowAttribute = (DWMWA_NCRENDERING_ENABLED = 1, DWMWA_NCRENDERING_POLICY, DWMWA_TRANSITIONS_FORCEDISABLED, DWMWA_ALLOW_NCPAINT, DWMWA_CAPTION_BUTTON_BOUNDS, DWMWA_NONCLIENT_RTL_LAYOUT, DWMWA_FORCE_ICONIC_REPRESENTATION, DWMWA_FLIP3D_POLICY, DWMWA_EXTENDED_FRAME_BOUNDS, DWMWA_HAS_ICONIC_BITMAP, DWMWA_DISALLOW_PEEK, DWMWA_EXCLUDED_FROM_PEEK, DWMWA_CLOAK, DWMWA_CLOAKED, DWMWA_FREEZE_REPRESENTATION, DWMWA_PASSIVE_UPDATE_MODE, DWMWA_USE_HOSTBACKDROPBRUSH, DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19, DWMWA_USE_IMMERSIVE_DARK_MODE = 20, DWMWA_WINDOW_CORNER_PREFERENCE = 33, DWMWA_BORDER_COLOR, DWMWA_CAPTION_COLOR, DWMWA_TEXT_COLOR, DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, DWMWA_SYSTEMBACKDROP_TYPE, DWMWA_LAST);
|
||||||
|
|
||||||
|
TDWMWindowCornerPreference = (DWMWCP_DEFAULT = 0, DWMWCP_DONOTROUND = 1, DWMWCP_ROUND = 2, DWMWCP_ROUNDSMALL = 3);
|
||||||
|
|
||||||
|
TImmersiveHCCacheMode = (IHCM_USE_CACHED_VALUE, IHCM_REFRESH);
|
||||||
|
|
||||||
|
TPreferredAppMode = (DefaultMode, AllowDarkMode, ForceDarkMode, ForceLightMode, ModeMax);
|
||||||
|
|
||||||
|
TWindowCompositionAttribute = (WCA_UNDEFINED = 0, //
|
||||||
|
WCA_NCRENDERING_ENABLED = 1, //
|
||||||
|
WCA_NCRENDERING_POLICY = 2, //
|
||||||
|
WCA_TRANSITIONS_FORCEDISABLED = 3, //
|
||||||
|
WCA_ALLOW_NCPAINT = 4, //
|
||||||
|
WCA_CAPTION_BUTTON_BOUNDS = 5, //
|
||||||
|
WCA_NONCLIENT_RTL_LAYOUT = 6, //
|
||||||
|
WCA_FORCE_ICONIC_REPRESENTATION = 7, //
|
||||||
|
WCA_EXTENDED_FRAME_BOUNDS = 8, //
|
||||||
|
WCA_HAS_ICONIC_BITMAP = 9, //
|
||||||
|
WCA_THEME_ATTRIBUTES = 10, //
|
||||||
|
WCA_NCRENDERING_EXILED = 11, //
|
||||||
|
WCA_NCADORNMENTINFO = 12, //
|
||||||
|
WCA_EXCLUDED_FROM_LIVEPREVIEW = 13, //
|
||||||
|
WCA_VIDEO_OVERLAY_ACTIVE = 14, //
|
||||||
|
WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15, //
|
||||||
|
WCA_DISALLOW_PEEK = 16, //
|
||||||
|
WCA_CLOAK = 17, //
|
||||||
|
WCA_CLOAKED = 18, //
|
||||||
|
WCA_ACCENT_POLICY = 19, //
|
||||||
|
WCA_FREEZE_REPRESENTATION = 20, //
|
||||||
|
WCA_EVER_UNCLOAKED = 21, //
|
||||||
|
WCA_VISUAL_OWNER = 22, //
|
||||||
|
WCA_HOLOGRAPHIC = 23, //
|
||||||
|
WCA_EXCLUDED_FROM_DDA = 24, //
|
||||||
|
WCA_PASSIVEUPDATEMODE = 25, //
|
||||||
|
WCA_USEDARKMODECOLORS = 26, //
|
||||||
|
WCA_LAST = 27);
|
||||||
|
|
||||||
|
TWindowCompositionAttrib = TWindowCompositionAttribute;
|
||||||
|
|
||||||
|
WINDOWCOMPOSITIONATTRIBDATA = record
|
||||||
|
Attrib: TWindowCompositionAttribute;
|
||||||
|
pvData: Pointer;
|
||||||
|
cbData: SIZE_T;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TWindowCompositionAttribData = WINDOWCOMPOSITIONATTRIBDATA;
|
||||||
|
|
||||||
|
PWindowCompositionAttribData = ^TWindowCompositionAttribData;
|
||||||
|
|
||||||
|
TRtlGetNtVersionNumbers = procedure(var major, minor, build: DWORD); stdcall;
|
||||||
|
|
||||||
|
TSetWindowCompositionAttribute = function(hWnd: HWND; pData: PWindowCompositionAttribData): BOOL; stdcall;
|
||||||
|
|
||||||
|
TShouldAppsUseDarkMode = function: BOOL; stdcall;
|
||||||
|
|
||||||
|
TAllowDarkModeForWindow = function(hWnd: HWND; allow: BOOL): BOOL; stdcall;
|
||||||
|
|
||||||
|
TAllowDarkModeForApp = function(allow: BOOL): BOOL; stdcall;
|
||||||
|
|
||||||
|
TRefreshImmersiveColorPolicyState = procedure; stdcall;
|
||||||
|
|
||||||
|
TIsDarkModeAllowedForWindow = function(hWnd: HWND): BOOL; stdcall;
|
||||||
|
|
||||||
|
TGetIsImmersiveColorUsingHighContrast = function(mode: TImmersiveHCCacheMode): BOOL; stdcall;
|
||||||
|
|
||||||
|
TOpenNcThemeData = function(hWnd: HWND; pszClassList: LPCWSTR): THandle; stdcall;
|
||||||
|
|
||||||
|
TShouldSystemUseDarkMode = function: BOOL; stdcall;
|
||||||
|
|
||||||
|
TSetPreferredAppMode = function(appMode: TPreferredAppMode): TPreferredAppMode; stdcall;
|
||||||
|
|
||||||
|
TIsDarkModeAllowedForApp = function: BOOL; stdcall;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{$ELSE}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
unit DarkModeApi.Vcl;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Vcl.Forms;
|
||||||
|
|
||||||
|
type
|
||||||
|
TFormHelper = class helper for TForm
|
||||||
|
procedure SetWindowColorModeAsSystem;
|
||||||
|
procedure SetWindowColorMode(IsDark: Boolean);
|
||||||
|
class function SystemIsDarkMode: Boolean;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure SetWindowColorModeAsSystemFor(Handle: THandle);
|
||||||
|
|
||||||
|
procedure SetWindowColorModeFor(Handle: THandle; IsDark: Boolean);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
DarkModeApi, FMX.Platform.Win, Winapi.Windows;
|
||||||
|
|
||||||
|
procedure SetWindowColorModeAsSystemFor(Handle: THandle);
|
||||||
|
var
|
||||||
|
Value: LongBool;
|
||||||
|
begin
|
||||||
|
Value := IsDarkMode;
|
||||||
|
DwmSetWindowAttribute(Handle, ImmersiveDarkMode, Value, SizeOf(Value));
|
||||||
|
AllowDarkModeForWindow(Handle, Value);
|
||||||
|
AllowDarkModeForApp(Value);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure SetWindowColorModeFor(Handle: THandle; IsDark: Boolean);
|
||||||
|
var
|
||||||
|
Value: LongBool;
|
||||||
|
begin
|
||||||
|
Value := IsDark;
|
||||||
|
DwmSetWindowAttribute(Handle, ImmersiveDarkMode, Value, SizeOf(Value));
|
||||||
|
AllowDarkModeForWindow(Handle, Value);
|
||||||
|
AllowDarkModeForApp(Value);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TFormHelper }
|
||||||
|
|
||||||
|
procedure TFormHelper.SetWindowColorMode(IsDark: Boolean);
|
||||||
|
begin
|
||||||
|
SetWindowColorModeFor(handle, IsDark);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TFormHelper.SetWindowColorModeAsSystem;
|
||||||
|
begin
|
||||||
|
SetWindowColorModeAsSystemFor(Handle);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TFormHelper.SystemIsDarkMode: Boolean;
|
||||||
|
begin
|
||||||
|
Result := IsDarkMode;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
||||||
+255
@@ -0,0 +1,255 @@
|
|||||||
|
unit DarkModeApi;
|
||||||
|
|
||||||
|
{$IFDEF MSWINDOWS}
|
||||||
|
|
||||||
|
{$WARN SYMBOL_PLATFORM OFF}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
// See also https://github.com/adzm/win32-custom-menubar-aero-theme
|
||||||
|
|
||||||
|
uses
|
||||||
|
Winapi.Windows, DarkModeApi.Types;
|
||||||
|
|
||||||
|
function DwmSetWindowAttribute(hwnd: HWND; dwAttribute: DWORD; pvAttribute: Pointer; cbAttribute: DWORD): HResult; stdcall; overload;
|
||||||
|
|
||||||
|
function DwmSetWindowAttribute(hwnd: HWND; dwAttribute: TDwmWindowAttribute; var pvAttribute; cbAttribute: DWORD): HResult; stdcall; overload;
|
||||||
|
|
||||||
|
function DwmSetWindowAttribute(hwnd: HWND; dwAttribute: TDwmWindowAttribute; var pvAttribute: TDWMWindowCornerPreference; cbAttribute: DWORD): HResult; stdcall; overload;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables dark context menus which change automatically depending on the theme.
|
||||||
|
/// </summary>
|
||||||
|
procedure AllowDarkModeForApp(allow: BOOL); stdcall;
|
||||||
|
|
||||||
|
function AllowDarkModeForWindow(hWnd: HWND; allow: Boolean): Boolean; stdcall;
|
||||||
|
|
||||||
|
// See https://en.wikipedia.org/wiki/Windows_10_version_history
|
||||||
|
function CheckBuildNumber(buildNumber: DWORD): Boolean;
|
||||||
|
|
||||||
|
function IsWindows10OrGreater(buildNumber: DWORD = 10000): Boolean;
|
||||||
|
|
||||||
|
function IsWindows11OrGreater(buildNumber: DWORD = 22000): Boolean;
|
||||||
|
|
||||||
|
function IsDarkModeAllowedForWindow(hWnd: HWND): BOOL; stdcall;
|
||||||
|
|
||||||
|
procedure RefreshImmersiveColorPolicyState; stdcall;
|
||||||
|
|
||||||
|
procedure RefreshTitleBarThemeColor(hWnd: HWND);
|
||||||
|
|
||||||
|
function ShouldAppsUseDarkMode: BOOL; stdcall;
|
||||||
|
|
||||||
|
function ShouldSystemUseDarkMode: BOOL; stdcall;
|
||||||
|
|
||||||
|
function ImmersiveDarkMode: TDwmWindowAttribute;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks the system registry to see if Dark mode is enabled
|
||||||
|
/// </summary>
|
||||||
|
function IsDarkMode: Boolean;
|
||||||
|
|
||||||
|
const
|
||||||
|
LOAD_LIBRARY_SEARCH_SYSTEM32 = $00000800;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
System.Classes, System.SysUtils, DarkModeApi.Consts, System.Win.Registry;
|
||||||
|
|
||||||
|
var
|
||||||
|
_AllowDarkModeForApp: TAllowDarkModeForApp = nil;
|
||||||
|
_AllowDarkModeForWindow: TAllowDarkModeForWindow = nil;
|
||||||
|
_GetIsImmersiveColorUsingHighContrast: TGetIsImmersiveColorUsingHighContrast = nil;
|
||||||
|
_IsDarkModeAllowedForWindow: TIsDarkModeAllowedForWindow = nil;
|
||||||
|
_OpenNcThemeData: TOpenNcThemeData = nil;
|
||||||
|
_RefreshImmersiveColorPolicyState: TRefreshImmersiveColorPolicyState = nil;
|
||||||
|
_SetPreferredAppMode: TSetPreferredAppMode = nil;
|
||||||
|
_SetWindowCompositionAttribute: TSetWindowCompositionAttribute = nil;
|
||||||
|
_ShouldAppsUseDarkMode: TShouldAppsUseDarkMode = nil;
|
||||||
|
_ShouldSystemUseDarkMode: TShouldSystemUseDarkMode = nil;
|
||||||
|
GDarkModeSupported: BOOL = False; // changed type to BOOL
|
||||||
|
GDarkModeEnabled: BOOL = False;
|
||||||
|
GUxTheme: HMODULE = 0;
|
||||||
|
|
||||||
|
function DwmSetWindowAttribute(hwnd: hwnd; dwAttribute: DWORD; pvAttribute: Pointer; cbAttribute: DWORD): HResult; stdcall; overload; external Dwmapi name 'DwmSetWindowAttribute' delayed;
|
||||||
|
|
||||||
|
function DwmSetWindowAttribute(hwnd: hwnd; dwAttribute: TDwmWindowAttribute; var pvAttribute: TDWMWindowCornerPreference; cbAttribute: DWORD): HResult; stdcall; overload; external Dwmapi name 'DwmSetWindowAttribute' delayed;
|
||||||
|
|
||||||
|
procedure AllowDarkModeForApp(allow: BOOL);
|
||||||
|
begin
|
||||||
|
if Assigned(_AllowDarkModeForApp) then
|
||||||
|
_AllowDarkModeForApp(allow)
|
||||||
|
else if Assigned(_SetPreferredAppMode) then
|
||||||
|
begin
|
||||||
|
if allow then
|
||||||
|
_SetPreferredAppMode(TPreferredAppMode.AllowDarkMode)
|
||||||
|
else
|
||||||
|
_SetPreferredAppMode(TPreferredAppMode.DefaultMode);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function DwmSetWindowAttribute(hwnd: hwnd; dwAttribute: TDwmWindowAttribute; var pvAttribute; cbAttribute: DWORD): HResult;
|
||||||
|
begin
|
||||||
|
Result := DwmSetWindowAttribute(hwnd, Ord(dwAttribute), @pvAttribute, cbAttribute);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsDarkModeAllowedForWindow(hWnd: hWnd): BOOL;
|
||||||
|
begin
|
||||||
|
Result := Assigned(_IsDarkModeAllowedForWindow) and _IsDarkModeAllowedForWindow(hWnd);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetIsImmersiveColorUsingHighContrast(mode: TImmersiveHCCacheMode): BOOL;
|
||||||
|
begin
|
||||||
|
Result := Assigned(_GetIsImmersiveColorUsingHighContrast) and _GetIsImmersiveColorUsingHighContrast(mode);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ImmersiveDarkMode: TDwmWindowAttribute;
|
||||||
|
begin
|
||||||
|
if IsWindows10OrGreater(18985) then
|
||||||
|
Result := DWMWA_USE_IMMERSIVE_DARK_MODE
|
||||||
|
else
|
||||||
|
Result := DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure RefreshImmersiveColorPolicyState;
|
||||||
|
begin
|
||||||
|
if Assigned(_RefreshImmersiveColorPolicyState) then
|
||||||
|
_RefreshImmersiveColorPolicyState;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsDarkMode: Boolean;
|
||||||
|
var
|
||||||
|
LRegistry: TRegistry;
|
||||||
|
begin
|
||||||
|
LRegistry := TRegistry.Create;
|
||||||
|
try
|
||||||
|
LRegistry.RootKey := HKEY_CURRENT_USER;
|
||||||
|
LRegistry.OpenKeyReadOnly('\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize');
|
||||||
|
Result := not LRegistry.ReadBool('AppsUseLightTheme');
|
||||||
|
finally
|
||||||
|
LRegistry.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ShouldSystemUseDarkMode: BOOL;
|
||||||
|
begin
|
||||||
|
Result := Assigned(_ShouldSystemUseDarkMode) and _ShouldSystemUseDarkMode;
|
||||||
|
end;
|
||||||
|
function CheckBuildNumber(buildNumber: DWORD): Boolean;
|
||||||
|
begin
|
||||||
|
Result :=
|
||||||
|
IsWindows10OrGreater(20348) or
|
||||||
|
IsWindows10OrGreater(19045) or //
|
||||||
|
IsWindows10OrGreater(19044) or //
|
||||||
|
IsWindows10OrGreater(19043) or //
|
||||||
|
IsWindows10OrGreater(19042) or //
|
||||||
|
IsWindows10OrGreater(19041) or // 2004
|
||||||
|
IsWindows10OrGreater(18363) or // 1909
|
||||||
|
IsWindows10OrGreater(18362) or // 1903
|
||||||
|
IsWindows10OrGreater(17763); // 1809
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsWindows10OrGreater(buildNumber: DWORD): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (TOSVersion.Major > 10) or ((TOSVersion.Major = 10) and (TOSVersion.Minor = 0) and (DWORD(TOSVersion.Build) >= buildNumber));
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsWindows11OrGreater(buildNumber: DWORD): Boolean;
|
||||||
|
begin
|
||||||
|
Result := IsWindows10OrGreater(22000) or IsWindows10OrGreater(buildNumber);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function AllowDarkModeForWindow(hWnd: hWnd; allow: Boolean): Boolean;
|
||||||
|
begin
|
||||||
|
Result := GDarkModeSupported and _AllowDarkModeForWindow(hWnd, allow);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsHighContrast: Boolean;
|
||||||
|
var
|
||||||
|
highContrast: HIGHCONTRASTW;
|
||||||
|
begin
|
||||||
|
highContrast.cbSize := SizeOf(highContrast);
|
||||||
|
if SystemParametersInfo(SPI_GETHIGHCONTRAST, SizeOf(highContrast), @highContrast, Ord(False)) then
|
||||||
|
Result := highContrast.dwFlags and HCF_HIGHCONTRASTON <> 0
|
||||||
|
else
|
||||||
|
Result := False;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure RefreshTitleBarThemeColor(hWnd: hWnd);
|
||||||
|
var
|
||||||
|
LUseDark: BOOL;
|
||||||
|
LData: TWindowCompositionAttribData;
|
||||||
|
begin
|
||||||
|
LUseDark := _IsDarkModeAllowedForWindow(hWnd) and _ShouldAppsUseDarkMode and not IsHighContrast;
|
||||||
|
if TOSVersion.Build < 18362 then
|
||||||
|
SetProp(hWnd, 'UseImmersiveDarkModeColors', THandle(LUseDark))
|
||||||
|
else if Assigned(_SetWindowCompositionAttribute) then
|
||||||
|
begin
|
||||||
|
LData.Attrib := WCA_USEDARKMODECOLORS;
|
||||||
|
LData.pvData := @LUseDark;
|
||||||
|
LData.cbData := SizeOf(LUseDark);
|
||||||
|
_SetWindowCompositionAttribute(hWnd, @LData);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ShouldAppsUseDarkMode: BOOL;
|
||||||
|
begin
|
||||||
|
Result := Assigned(_ShouldAppsUseDarkMode) and _ShouldAppsUseDarkMode;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure InitDarkMode;
|
||||||
|
begin
|
||||||
|
if ((TOSVersion.Major = 10) and (TOSVersion.Minor = 0) and CheckBuildNumber(TOSVersion.Build)) then
|
||||||
|
begin
|
||||||
|
GUxTheme := LoadLibraryEx('uxtheme.dll', 0, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||||
|
if GUxTheme <> 0 then
|
||||||
|
begin
|
||||||
|
@_AllowDarkModeForWindow := GetProcAddress(GUxTheme, MAKEINTRESOURCEA(133));
|
||||||
|
@_GetIsImmersiveColorUsingHighContrast := GetProcAddress(GUxTheme, MAKEINTRESOURCEA(106));
|
||||||
|
@_IsDarkModeAllowedForWindow := GetProcAddress(GUxTheme, MAKEINTRESOURCEA(137));
|
||||||
|
@_RefreshImmersiveColorPolicyState := GetProcAddress(GUxTheme, MAKEINTRESOURCEA(104));
|
||||||
|
@_SetWindowCompositionAttribute := GetProcAddress(GetModuleHandle(user32), 'SetWindowCompositionAttribute');
|
||||||
|
@_ShouldAppsUseDarkMode := GetProcAddress(GUxTheme, MAKEINTRESOURCEA(132));
|
||||||
|
|
||||||
|
var P := GetProcAddress(GUxTheme, MAKEINTRESOURCEA(135));
|
||||||
|
if TOSVersion.Build < 18362 then
|
||||||
|
@_AllowDarkModeForApp := P
|
||||||
|
else
|
||||||
|
@_SetPreferredAppMode := P;
|
||||||
|
|
||||||
|
if Assigned(_RefreshImmersiveColorPolicyState) and
|
||||||
|
Assigned(_ShouldAppsUseDarkMode) and Assigned(_AllowDarkModeForWindow) and
|
||||||
|
(Assigned(_AllowDarkModeForApp) or Assigned(_SetPreferredAppMode)) and
|
||||||
|
Assigned(_IsDarkModeAllowedForWindow) then
|
||||||
|
begin
|
||||||
|
GDarkModeSupported := True;
|
||||||
|
AllowDarkModeForApp(True);
|
||||||
|
_RefreshImmersiveColorPolicyState;
|
||||||
|
GDarkModeEnabled := ShouldAppsUseDarkMode and not IsHighContrast;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DoneDarkMode;
|
||||||
|
begin
|
||||||
|
if GUxTheme <> 0 then
|
||||||
|
FreeLibrary(GUxTheme);
|
||||||
|
end;
|
||||||
|
|
||||||
|
initialization
|
||||||
|
InitDarkMode;
|
||||||
|
|
||||||
|
finalization
|
||||||
|
DoneDarkMode;
|
||||||
|
|
||||||
|
{$ELSE}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 alinvip22@gmail.com
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
Reference in New Issue
Block a user