WinRT apps check if the Windows theme is set to dark mode through IUISettings3::GetColorValue().
An option needs to be added to Winecfg to enable dark mode support, which just sets the registry key AppsUseLightTheme to 0 for dark mode and 1 for light mode. It will have to be in a separate merge request. Also, not sure if a dark mode checkbox should be added or if dark mode should be automatically set based on the loaded theme in Wine. Though, for the latter there needs to be a property that returns the mode of the theme. Name alone might not be sufficient.
Marking this as draft because I'm not sure what I'm doing wrong with the test. It's returning E_NOINTERFACE for IUISettings3.
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- include/Makefile.in | 1 + include/windows.ui.viewmanagement.idl | 305 ++++++++++++++++++++++++++ 2 files changed, 306 insertions(+) create mode 100644 include/windows.ui.viewmanagement.idl
diff --git a/include/Makefile.in b/include/Makefile.in index 8602dd51e42..b9a357ef366 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -824,6 +824,7 @@ SOURCES = \ windows.system.threading.idl \ windows.system.userprofile.idl \ windows.ui.idl \ + windows.ui.viewmanagement.idl \ windowscontracts.idl \ windowsx.h \ wine/afd.h \ diff --git a/include/windows.ui.viewmanagement.idl b/include/windows.ui.viewmanagement.idl new file mode 100644 index 00000000000..a416635fd5b --- /dev/null +++ b/include/windows.ui.viewmanagement.idl @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2023 Mohamad Al-Jaf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef __WIDL__ +#pragma winrt ns_prefix +#endif + +import "inspectable.idl"; +import "asyncinfo.idl"; +import "eventtoken.idl"; +import "windowscontracts.idl"; +import "windows.foundation.idl"; +import "windows.devices.enumeration.idl"; +/* import "windows.phone.idl"; */ +import "windows.ui.idl"; +/* import "windows.ui.core.idl"; */ +/* import "windows.ui.popups.idl"; */ +/* import "windows.ui.windowmanagement.idl"; */ + +namespace Windows.UI.ViewManagement +{ + typedef enum HandPreference HandPreference; + typedef enum UIColorType UIColorType; + typedef enum UIElementType UIElementType; + + interface IUISettings; + interface IUISettings2; + interface IUISettings3; + interface IUISettings4; + interface IUISettings5; + interface IUISettings6; + interface IUISettingsAnimationsEnabledChangedEventArgs; + interface IUISettingsAutoHideScrollBarsChangedEventArgs; + interface IUISettingsMessageDurationChangedEventArgs; + + runtimeclass UISettings; + runtimeclass UISettingsAnimationsEnabledChangedEventArgs; + runtimeclass UISettingsAutoHideScrollBarsChangedEventArgs; + runtimeclass UISettingsMessageDurationChangedEventArgs; + + declare { + interface Windows.Foundation.IReference<Windows.UI.ViewManagement.UIElementType>; + interface Windows.Foundation.TypedEventHandler<Windows.UI.ViewManagement.UISettings *, IInspectable *>; + interface Windows.Foundation.TypedEventHandler<Windows.UI.ViewManagement.UISettings *, Windows.UI.ViewManagement.UISettingsAnimationsEnabledChangedEventArgs *>; + interface Windows.Foundation.TypedEventHandler<Windows.UI.ViewManagement.UISettings *, Windows.UI.ViewManagement.UISettingsAutoHideScrollBarsChangedEventArgs *>; + interface Windows.Foundation.TypedEventHandler<Windows.UI.ViewManagement.UISettings *, Windows.UI.ViewManagement.UISettingsMessageDurationChangedEventArgs *>; + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0) + ] + enum HandPreference + { + LeftHanded = 0, + RightHanded = 1, + }; + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0) + ] + enum UIColorType + { + Background = 0, + Foreground = 1, + AccentDark3 = 2, + AccentDark2 = 3, + AccentDark1 = 4, + Accent = 5, + AccentLight1 = 6, + AccentLight2 = 7, + AccentLight3 = 8, + Complement = 9, + }; + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0) + ] + enum UIElementType + { + ActiveCaption = 0, + Background = 1, + ButtonFace = 2, + ButtonText = 3, + CaptionText = 4, + GrayText = 5, + Highlight = 6, + HighlightText = 7, + Hotlight = 8, + InactiveCaption = 9, + InactiveCaptionText = 10, + Window = 11, + WindowText = 12, + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + AccentColor = 1000, + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + TextHigh = 1001, + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + TextMedium = 1002, + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + TextLow = 1003, + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + TextContrastWithHigh = 1004, + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + NonTextHigh = 1005, + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + NonTextMediumHigh = 1006, + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + NonTextMedium = 1007, + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + NonTextMediumLow = 1008, + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + NonTextLow = 1009, + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + PageBackground = 1010, + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + PopupBackground = 1011, + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + OverlayOutsidePopup = 1012, + }; + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.UI.ViewManagement.UISettings), + uuid(85361600-1c63-4627-bcb1-3a89e0bc9c55) + ] + interface IUISettings : IInspectable + { + [propget] HRESULT HandPreference([out, retval] Windows.UI.ViewManagement.HandPreference *value); + [propget] HRESULT CursorSize([out, retval] Windows.Foundation.Size *value); + [propget] HRESULT ScrollBarSize([out, retval] Windows.Foundation.Size *value); + [propget] HRESULT ScrollBarArrowSize([out, retval] Windows.Foundation.Size *value); + [propget] HRESULT ScrollBarThumbBoxSize([out, retval] Windows.Foundation.Size *value); + [propget] HRESULT MessageDuration([out, retval] UINT32 *value); + [propget] HRESULT AnimationsEnabled([out, retval] boolean *value); + [propget] HRESULT CaretBrowsingEnabled([out, retval] boolean *value); + [propget] HRESULT CaretBlinkRate([out, retval] UINT32 *value); + [propget] HRESULT CaretWidth([out, retval] UINT32 *value); + [propget] HRESULT DoubleClickTime([out, retval] UINT32 *value); + [propget] HRESULT MouseHoverTime([out, retval] UINT32 *value); + HRESULT UIElementColor([in] Windows.UI.ViewManagement.UIElementType element, [out, retval] Windows.UI.Color *value); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.UI.ViewManagement.UISettings), + uuid(bad82401-2721-44f9-bb91-2bb228be442f) + ] + interface IUISettings2 : IInspectable + { + [propget] HRESULT TextScaleFactor([out, retval] DOUBLE *value); + [eventadd] HRESULT TextScaleFactorChanged( + [in] Windows.Foundation.TypedEventHandler<Windows.UI.ViewManagement.UISettings *, IInspectable *> *handler, + [out, retval] EventRegistrationToken *cookie + ); + [eventremove] HRESULT TextScaleFactorChanged([in] EventRegistrationToken cookie); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.UI.ViewManagement.UISettings), + uuid(03021be4-5254-4781-8194-5168f7d06d7b) + ] + interface IUISettings3 : IInspectable + { + HRESULT GetColorValue([in] Windows.UI.ViewManagement.UIColorType color, [out, retval] Windows.UI.Color *value); + [eventadd] HRESULT ColorValuesChanged( + [in] Windows.Foundation.TypedEventHandler<Windows.UI.ViewManagement.UISettings *, IInspectable *> *handler, + [out, retval] EventRegistrationToken *cookie + ); + [eventremove] HRESULT ColorValuesChanged([in] EventRegistrationToken cookie); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 4.0), + exclusiveto(Windows.UI.ViewManagement.UISettings), + uuid(52bb3002-919b-4d6b-9b78-8dd66ff4b93b) + ] + interface IUISettings4 : IInspectable + { + [propget] HRESULT AdvancedEffectsEnabled([out, retval] boolean *value); + [eventadd] HRESULT AdvancedEffectsEnabledChanged( + [in] Windows.Foundation.TypedEventHandler<Windows.UI.ViewManagement.UISettings *, IInspectable *> *handler, + [out, retval] EventRegistrationToken *cookie + ); + [eventremove] HRESULT AdvancedEffectsEnabledChanged([in] EventRegistrationToken cookie); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 8.0), + exclusiveto(Windows.UI.ViewManagement.UISettings), + uuid(5349d588-0cb5-5f05-bd34-706b3231f0bd) + ] + interface IUISettings5 : IInspectable + { + [propget] HRESULT AutoHideScrollBars([out, retval] boolean *value); + [eventadd] HRESULT AutoHideScrollBarsChanged( + [in] Windows.Foundation.TypedEventHandler<Windows.UI.ViewManagement.UISettings *,Windows.UI.ViewManagement.UISettingsAutoHideScrollBarsChangedEventArgs *> *handler, + [out, retval] EventRegistrationToken *token + ); + [eventremove] HRESULT AutoHideScrollBarsChanged([in] EventRegistrationToken token); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 10.0), + exclusiveto(Windows.UI.ViewManagement.UISettings), + uuid(aef19bd7-fe31-5a04-ada4-469aaec6dfa9) + ] + interface IUISettings6 : IInspectable + { + [eventadd] HRESULT AnimationsEnabledChanged( + [in] Windows.Foundation.TypedEventHandler<Windows.UI.ViewManagement.UISettings *, Windows.UI.ViewManagement.UISettingsAnimationsEnabledChangedEventArgs *> *handler, + [out, retval] EventRegistrationToken *token + ); + [eventremove] HRESULT AnimationsEnabledChanged([in] EventRegistrationToken token); + [eventadd] HRESULT MessageDurationChanged( + [in] Windows.Foundation.TypedEventHandler<Windows.UI.ViewManagement.UISettings *, Windows.UI.ViewManagement.UISettingsMessageDurationChangedEventArgs *> *handler, + [out, retval] EventRegistrationToken *token + ); + [eventremove] HRESULT MessageDurationChanged([in] EventRegistrationToken token); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 10.0), + exclusiveto(Windows.UI.ViewManagement.UISettingsAnimationsEnabledChangedEventArgs), + uuid(0c7b4b3d-2ea1-533e-894d-415bc5243c29) + ] + interface IUISettingsAnimationsEnabledChangedEventArgs : IInspectable + { + } + + [ + contract(Windows.Foundation.UniversalApiContract, 8.0), + exclusiveto(Windows.UI.ViewManagement.UISettingsAutoHideScrollBarsChangedEventArgs), + uuid(87afd4b2-9146-5f02-8f6b-06d454174c0f) + ] + interface IUISettingsAutoHideScrollBarsChangedEventArgs : IInspectable + { + } + + [ + contract(Windows.Foundation.UniversalApiContract, 10.0), + exclusiveto(Windows.UI.ViewManagement.UISettingsMessageDurationChangedEventArgs), + uuid(338aad52-4a5d-5b59-8002-d930f608fd6e) + ] + interface IUISettingsMessageDurationChangedEventArgs : IInspectable + { + } + + [ + activatable(Windows.Foundation.UniversalApiContract, 1.0), + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile) + ] + runtimeclass UISettings + { + [default] interface Windows.UI.ViewManagement.IUISettings; + [contract(Windows.Foundation.UniversalApiContract, 1.0)] interface Windows.UI.ViewManagement.IUISettings2; + [contract(Windows.Foundation.UniversalApiContract, 1.0)] interface Windows.UI.ViewManagement.IUISettings3; + [contract(Windows.Foundation.UniversalApiContract, 4.0)] interface Windows.UI.ViewManagement.IUISettings4; + [contract(Windows.Foundation.UniversalApiContract, 8.0)] interface Windows.UI.ViewManagement.IUISettings5; + [contract(Windows.Foundation.UniversalApiContract, 10.0)] interface Windows.UI.ViewManagement.IUISettings6; + } + + [ + contract(Windows.Foundation.UniversalApiContract, 10.0), + marshaling_behavior(agile) + ] + runtimeclass UISettingsAnimationsEnabledChangedEventArgs + { + [default] interface Windows.UI.ViewManagement.IUISettingsAnimationsEnabledChangedEventArgs; + } + + [ + contract(Windows.Foundation.UniversalApiContract, 8.0), + marshaling_behavior(agile) + ] + runtimeclass UISettingsAutoHideScrollBarsChangedEventArgs + { + [default] interface Windows.UI.ViewManagement.IUISettingsAutoHideScrollBarsChangedEventArgs; + } + + [ + contract(Windows.Foundation.UniversalApiContract, 10.0), + marshaling_behavior(agile) + ] + runtimeclass UISettingsMessageDurationChangedEventArgs + { + [default] interface Windows.UI.ViewManagement.IUISettingsMessageDurationChangedEventArgs; + } +}
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- configure.ac | 2 + dlls/windows.ui/Makefile.in | 9 +++ dlls/windows.ui/classes.idl | 23 ++++++ dlls/windows.ui/main.c | 55 ++++++++++++++ dlls/windows.ui/private.h | 41 ++++++++++ dlls/windows.ui/tests/Makefile.in | 5 ++ dlls/windows.ui/tests/uisettings.c | 90 ++++++++++++++++++++++ dlls/windows.ui/uisettings.c | 116 +++++++++++++++++++++++++++++ dlls/windows.ui/windows.ui.spec | 12 +++ 9 files changed, 353 insertions(+) create mode 100644 dlls/windows.ui/Makefile.in create mode 100644 dlls/windows.ui/classes.idl create mode 100644 dlls/windows.ui/main.c create mode 100644 dlls/windows.ui/private.h create mode 100644 dlls/windows.ui/tests/Makefile.in create mode 100644 dlls/windows.ui/tests/uisettings.c create mode 100644 dlls/windows.ui/uisettings.c create mode 100644 dlls/windows.ui/windows.ui.spec
diff --git a/configure.ac b/configure.ac index 9ff7c5e8914..2581e115a79 100644 --- a/configure.ac +++ b/configure.ac @@ -3127,6 +3127,8 @@ WINE_CONFIG_MAKEFILE(dlls/windows.media/tests) WINE_CONFIG_MAKEFILE(dlls/windows.networking) WINE_CONFIG_MAKEFILE(dlls/windows.system.profile.systemmanufacturers) WINE_CONFIG_MAKEFILE(dlls/windows.system.profile.systemmanufacturers/tests) +WINE_CONFIG_MAKEFILE(dlls/windows.ui) +WINE_CONFIG_MAKEFILE(dlls/windows.ui/tests) WINE_CONFIG_MAKEFILE(dlls/windowscodecs) WINE_CONFIG_MAKEFILE(dlls/windowscodecs/tests) WINE_CONFIG_MAKEFILE(dlls/windowscodecsext) diff --git a/dlls/windows.ui/Makefile.in b/dlls/windows.ui/Makefile.in new file mode 100644 index 00000000000..cb9b48a664b --- /dev/null +++ b/dlls/windows.ui/Makefile.in @@ -0,0 +1,9 @@ +MODULE = windows.ui.dll +IMPORTS = combase + +C_SRCS = \ + main.c \ + uisettings.c + +IDL_SRCS = \ + classes.idl diff --git a/dlls/windows.ui/classes.idl b/dlls/windows.ui/classes.idl new file mode 100644 index 00000000000..e6680b2e550 --- /dev/null +++ b/dlls/windows.ui/classes.idl @@ -0,0 +1,23 @@ +/* + * Runtime Classes for windows.ui.dll + * + * Copyright (C) 2023 Mohamad Al-Jaf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma makedep register + +#include "windows.ui.viewmanagement.idl" diff --git a/dlls/windows.ui/main.c b/dlls/windows.ui/main.c new file mode 100644 index 00000000000..8896e0d1e71 --- /dev/null +++ b/dlls/windows.ui/main.c @@ -0,0 +1,55 @@ +/* WinRT Windows.UI Implementation + * + * Copyright (C) 2023 Mohamad Al-Jaf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "initguid.h" +#include "private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ui); + +static const char *debugstr_hstring( HSTRING hstr ) +{ + const WCHAR *str; + UINT32 len; + if (hstr && !((ULONG_PTR)hstr >> 16)) return "(invalid)"; + str = WindowsGetStringRawBuffer( hstr, &len ); + return wine_dbgstr_wn( str, len ); +} + +HRESULT WINAPI DllGetClassObject( REFCLSID clsid, REFIID riid, void **out ) +{ + FIXME( "clsid %s, riid %s, out %p stub!\n", debugstr_guid(clsid), debugstr_guid(riid), out ); + return CLASS_E_CLASSNOTAVAILABLE; +} + +HRESULT WINAPI DllGetActivationFactory( HSTRING classid, IActivationFactory **factory ) +{ + const WCHAR *buffer = WindowsGetStringRawBuffer( classid, NULL ); + + TRACE( "class %s, factory %p.\n", debugstr_hstring(classid), factory ); + + *factory = NULL; + + if (!wcscmp( buffer, RuntimeClass_Windows_UI_ViewManagement_UISettings )) + IActivationFactory_QueryInterface( uisettings_factory, &IID_IActivationFactory, (void **)factory ); + + if (*factory) return S_OK; + return CLASS_E_CLASSNOTAVAILABLE; +} diff --git a/dlls/windows.ui/private.h b/dlls/windows.ui/private.h new file mode 100644 index 00000000000..1af5faf152b --- /dev/null +++ b/dlls/windows.ui/private.h @@ -0,0 +1,41 @@ +/* WinRT Windows.UI Implementation + * + * Copyright (C) 2023 Mohamad Al-Jaf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_WINDOWS_UI_PRIVATE_H +#define __WINE_WINDOWS_UI_PRIVATE_H + +#include <stdarg.h> + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" +#include "winstring.h" + +#include "activation.h" + +#define WIDL_using_Windows_Foundation +#include "windows.foundation.h" +#define WIDL_using_Windows_UI +#include "windows.ui.h" +#define WIDL_using_Windows_UI_ViewManagement +#include "windows.ui.viewmanagement.h" + +extern IActivationFactory *uisettings_factory; + +#endif diff --git a/dlls/windows.ui/tests/Makefile.in b/dlls/windows.ui/tests/Makefile.in new file mode 100644 index 00000000000..4c587f17f23 --- /dev/null +++ b/dlls/windows.ui/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = windows.ui.dll +IMPORTS = combase + +C_SRCS = \ + uisettings.c diff --git a/dlls/windows.ui/tests/uisettings.c b/dlls/windows.ui/tests/uisettings.c new file mode 100644 index 00000000000..18603e53d46 --- /dev/null +++ b/dlls/windows.ui/tests/uisettings.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2023 Mohamad Al-Jaf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#define COBJMACROS +#include "initguid.h" +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winstring.h" + +#include "roapi.h" + +#define WIDL_using_Windows_Foundation +#include "windows.foundation.h" +#define WIDL_using_Windows_UI +#include "windows.ui.h" +#define WIDL_using_Windows_UI_ViewManagement +#include "windows.ui.viewmanagement.h" + +#include "wine/test.h" + +#define check_interface( obj, iid, exp ) check_interface_( __LINE__, obj, iid, exp ) +static void check_interface_( unsigned int line, void *obj, const IID *iid, BOOL supported ) +{ + IUnknown *iface = obj; + IUnknown *unk; + HRESULT hr, expected_hr; + + expected_hr = supported ? S_OK : E_NOINTERFACE; + + hr = IUnknown_QueryInterface( iface, iid, (void **)&unk ); + ok_( __FILE__, line )( hr == expected_hr, "Got hr %#lx, expected %#lx.\n", hr, expected_hr ); + if (SUCCEEDED(hr)) + IUnknown_Release( unk ); +} + +static void test_UISettings_Statics(void) +{ + static const WCHAR *uisettings_name = L"Windows.UI.ViewManagement.UISettings"; + IActivationFactory *factory; + HSTRING str; + HRESULT hr; + LONG ref; + + hr = WindowsCreateString( uisettings_name, wcslen( uisettings_name ), &str ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + + hr = RoGetActivationFactory( str, &IID_IActivationFactory, (void **)&factory ); + WindowsDeleteString( str ); + ok( hr == S_OK || broken( hr == REGDB_E_CLASSNOTREG ), "got hr %#lx.\n", hr ); + if (hr == REGDB_E_CLASSNOTREG) + { + win_skip( "%s runtimeclass not registered, skipping tests.\n", wine_dbgstr_w( uisettings_name )); + return; + } + + check_interface( factory, &IID_IUnknown, TRUE ); + check_interface( factory, &IID_IInspectable, TRUE ); + check_interface( factory, &IID_IAgileObject, FALSE ); + + ref = IActivationFactory_Release( factory ); + ok( ref == 1, "got ref %ld.\n", ref ); +} + +START_TEST(uisettings) +{ + HRESULT hr; + + hr = RoInitialize( RO_INIT_MULTITHREADED ); + ok( hr == S_OK, "RoInitialize failed, hr %#lx\n", hr ); + + test_UISettings_Statics(); + + RoUninitialize(); +} diff --git a/dlls/windows.ui/uisettings.c b/dlls/windows.ui/uisettings.c new file mode 100644 index 00000000000..1ce1096d708 --- /dev/null +++ b/dlls/windows.ui/uisettings.c @@ -0,0 +1,116 @@ +/* WinRT Windows.UI Implementation + * + * Copyright (C) 2023 Mohamad Al-Jaf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ui); + +struct uisettings_statics +{ + IActivationFactory IActivationFactory_iface; + LONG ref; +}; + +static inline struct uisettings_statics *impl_from_IActivationFactory( IActivationFactory *iface ) +{ + return CONTAINING_RECORD( iface, struct uisettings_statics, IActivationFactory_iface ); +} + +static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) +{ + struct uisettings_statics *impl = impl_from_IActivationFactory( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IActivationFactory )) + { + *out = &impl->IActivationFactory_iface; + IInspectable_AddRef( *out ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI factory_AddRef( IActivationFactory *iface ) +{ + struct uisettings_statics *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI factory_Release( IActivationFactory *iface ) +{ + struct uisettings_statics *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static HRESULT WINAPI factory_GetIids( IActivationFactory *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance ) +{ + FIXME( "iface %p, instance %p stub!\n", iface, instance ); + return E_NOTIMPL; +} + +static const struct IActivationFactoryVtbl factory_vtbl = +{ + factory_QueryInterface, + factory_AddRef, + factory_Release, + /* IInspectable methods */ + factory_GetIids, + factory_GetRuntimeClassName, + factory_GetTrustLevel, + /* IActivationFactory methods */ + factory_ActivateInstance, +}; + +static struct uisettings_statics uisettings_statics = +{ + {&factory_vtbl}, + 1, +}; + +IActivationFactory *uisettings_factory = &uisettings_statics.IActivationFactory_iface; diff --git a/dlls/windows.ui/windows.ui.spec b/dlls/windows.ui/windows.ui.spec new file mode 100644 index 00000000000..21c440bb844 --- /dev/null +++ b/dlls/windows.ui/windows.ui.spec @@ -0,0 +1,12 @@ +# @ stub WINDOWS.UI_1500 +@ stdcall -private DllCanUnloadNow() +@ stdcall -private DllGetActivationFactory(ptr ptr) +@ stdcall -private DllGetClassObject(ptr ptr ptr) +@ stdcall -private DllRegisterServer() +@ stdcall -private DllUnregisterServer() +# @ stub WINDOWS.UI_1600 +@ stub CreateControlInput +# @ stub WINDOWS.UI_1602 +@ stub CreateControlInputEx +# @ stub WINDOWS.UI_1604 +# @ stub WINDOWS.UI_1700
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- dlls/windows.ui/private.h | 38 ++++++++++++++++++++++++++ dlls/windows.ui/tests/uisettings.c | 17 ++++++++++++ dlls/windows.ui/uisettings.c | 44 ++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+)
diff --git a/dlls/windows.ui/private.h b/dlls/windows.ui/private.h index 1af5faf152b..60a928ca865 100644 --- a/dlls/windows.ui/private.h +++ b/dlls/windows.ui/private.h @@ -38,4 +38,42 @@
extern IActivationFactory *uisettings_factory;
+#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \ + static inline impl_type *impl_from( iface_type *iface ) \ + { \ + return CONTAINING_RECORD( iface, impl_type, iface_mem ); \ + } \ + static HRESULT WINAPI pfx##_QueryInterface( iface_type *iface, REFIID iid, void **out ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_QueryInterface( (IInspectable *)(expr), iid, out ); \ + } \ + static ULONG WINAPI pfx##_AddRef( iface_type *iface ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_AddRef( (IInspectable *)(expr) ); \ + } \ + static ULONG WINAPI pfx##_Release( iface_type *iface ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_Release( (IInspectable *)(expr) ); \ + } \ + static HRESULT WINAPI pfx##_GetIids( iface_type *iface, ULONG *iid_count, IID **iids ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetIids( (IInspectable *)(expr), iid_count, iids ); \ + } \ + static HRESULT WINAPI pfx##_GetRuntimeClassName( iface_type *iface, HSTRING *class_name ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetRuntimeClassName( (IInspectable *)(expr), class_name ); \ + } \ + static HRESULT WINAPI pfx##_GetTrustLevel( iface_type *iface, TrustLevel *trust_level ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetTrustLevel( (IInspectable *)(expr), trust_level ); \ + } +#define DEFINE_IINSPECTABLE( pfx, iface_type, impl_type, base_iface ) \ + DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, &impl->base_iface ) + #endif diff --git a/dlls/windows.ui/tests/uisettings.c b/dlls/windows.ui/tests/uisettings.c index 18603e53d46..c4a67c8eb28 100644 --- a/dlls/windows.ui/tests/uisettings.c +++ b/dlls/windows.ui/tests/uisettings.c @@ -52,7 +52,9 @@ static void check_interface_( unsigned int line, void *obj, const IID *iid, BOOL static void test_UISettings_Statics(void) { static const WCHAR *uisettings_name = L"Windows.UI.ViewManagement.UISettings"; + IUISettings3 *uisettings_statics3; IActivationFactory *factory; + IInspectable *inspectable; HSTRING str; HRESULT hr; LONG ref; @@ -73,6 +75,21 @@ static void test_UISettings_Statics(void) check_interface( factory, &IID_IInspectable, TRUE ); check_interface( factory, &IID_IAgileObject, FALSE );
+ hr = IActivationFactory_QueryInterface( factory, &IID_IInspectable, (void **)&inspectable ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + + hr = IActivationFactory_QueryInterface( factory, &IID_IUISettings3, (void **)&uisettings_statics3 ); + ok( hr == S_OK || broken( hr == E_NOINTERFACE ), "got hr %#lx\n", hr ); + if (FAILED( hr )) + { + win_skip( "IUISettings3 not supported.\n" ); + goto skip_uisettings_statics3; + } + + IUISettings3_Release( uisettings_statics3 ); + +skip_uisettings_statics3: + IInspectable_Release( inspectable ); ref = IActivationFactory_Release( factory ); ok( ref == 1, "got ref %ld.\n", ref ); } diff --git a/dlls/windows.ui/uisettings.c b/dlls/windows.ui/uisettings.c index 1ce1096d708..f2ae024de1b 100644 --- a/dlls/windows.ui/uisettings.c +++ b/dlls/windows.ui/uisettings.c @@ -26,6 +26,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(ui); struct uisettings_statics { IActivationFactory IActivationFactory_iface; + IUISettings3 IUISettings3_iface; LONG ref; };
@@ -49,6 +50,13 @@ static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID return S_OK; }
+ if (IsEqualGUID( iid, &IID_IUISettings3 )) + { + *out = &impl->IUISettings3_iface; + IInspectable_AddRef( *out ); + return S_OK; + } + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); *out = NULL; return E_NOINTERFACE; @@ -107,9 +115,45 @@ static const struct IActivationFactoryVtbl factory_vtbl = factory_ActivateInstance, };
+DEFINE_IINSPECTABLE( statics3, IUISettings3, struct uisettings_statics, IActivationFactory_iface ) + +static HRESULT WINAPI statics3_GetColorValue( IUISettings3 *iface, UIColorType type, Color *value ) +{ + FIXME( "iface %p, type %d, color %p stub!\n", iface, type, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI statics3_add_ColorValuesChanged( IUISettings3 *iface, ITypedEventHandler_UISettings_IInspectable *handler, EventRegistrationToken *cookie ) +{ + FIXME( "iface %p, handler %p, cookie %p stub!\n", iface, handler, cookie ); + return E_NOTIMPL; +} + +static HRESULT WINAPI statics3_remove_ColorValuesChanged( IUISettings3 *iface, EventRegistrationToken cookie ) +{ + FIXME( "iface %p, cookie %#I64x stub!\n", iface, cookie.value ); + return E_NOTIMPL; +} + +static const struct IUISettings3Vtbl statics3_vtbl = +{ + statics3_QueryInterface, + statics3_AddRef, + statics3_Release, + /* IInspectable methods */ + statics3_GetIids, + statics3_GetRuntimeClassName, + statics3_GetTrustLevel, + /* IUISettings3 methods */ + statics3_GetColorValue, + statics3_add_ColorValuesChanged, + statics3_remove_ColorValuesChanged, +}; + static struct uisettings_statics uisettings_statics = { {&factory_vtbl}, + {&statics3_vtbl}, 1, };
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- dlls/windows.ui/Makefile.in | 2 +- dlls/windows.ui/uisettings.c | 45 ++++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 3 deletions(-)
diff --git a/dlls/windows.ui/Makefile.in b/dlls/windows.ui/Makefile.in index cb9b48a664b..592d023f353 100644 --- a/dlls/windows.ui/Makefile.in +++ b/dlls/windows.ui/Makefile.in @@ -1,5 +1,5 @@ MODULE = windows.ui.dll -IMPORTS = combase +IMPORTS = combase advapi32
C_SRCS = \ main.c \ diff --git a/dlls/windows.ui/uisettings.c b/dlls/windows.ui/uisettings.c index f2ae024de1b..7f120eafbdb 100644 --- a/dlls/windows.ui/uisettings.c +++ b/dlls/windows.ui/uisettings.c @@ -117,10 +117,51 @@ static const struct IActivationFactoryVtbl factory_vtbl =
DEFINE_IINSPECTABLE( statics3, IUISettings3, struct uisettings_statics, IActivationFactory_iface )
+static DWORD get_windows_color_mode(void) +{ + static const WCHAR *subkey = L"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"; + static const WCHAR *name = L"AppsUseLightTheme"; + static const HKEY root = HKEY_CURRENT_USER; + DWORD ret, len = sizeof(ret), type; + HKEY hkey; + + if (RegOpenKeyExW( root, subkey, 0, KEY_QUERY_VALUE, &hkey )) return 1; + if (RegQueryValueExW( hkey, name, NULL, &type, (BYTE *)&ret, &len ) || type != REG_DWORD) ret = 1; + RegCloseKey( hkey ); + return ret; +} + +static void set_color_value( BYTE a, BYTE r, BYTE g, BYTE b, Color *out ) +{ + out->A = a; + out->R = r; + out->G = g; + out->B = b; +} + static HRESULT WINAPI statics3_GetColorValue( IUISettings3 *iface, UIColorType type, Color *value ) { - FIXME( "iface %p, type %d, color %p stub!\n", iface, type, value ); - return E_NOTIMPL; + DWORD light_theme; + + TRACE( "iface %p, type %d, value %p.\n", iface, type, value ); + + switch (type) { + case UIColorType_Foreground: + case UIColorType_Background: + light_theme = get_windows_color_mode(); + break; + default: + FIXME( "type %d not implemented.\n", type ); + return E_NOTIMPL; + } + + if (type == UIColorType_Foreground) + set_color_value( 0, light_theme ? 0 : 255, light_theme ? 0 : 255, light_theme ? 0 : 255, value ); + else + set_color_value( 0, light_theme ? 255 : 0, light_theme ? 255 : 0, light_theme ? 255 : 0, value ); + + TRACE( "Returning value.A = %d, value.R = %d, value.G = %d, value.B = %d\n", value->A, value->R, value->G, value->B ); + return S_OK; }
static HRESULT WINAPI statics3_add_ColorValuesChanged( IUISettings3 *iface, ITypedEventHandler_UISettings_IInspectable *handler, EventRegistrationToken *cookie )
From: Mohamad Al-Jaf mohamadaljaf@gmail.com
--- dlls/windows.ui/tests/uisettings.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/dlls/windows.ui/tests/uisettings.c b/dlls/windows.ui/tests/uisettings.c index c4a67c8eb28..e1226cd3f7c 100644 --- a/dlls/windows.ui/tests/uisettings.c +++ b/dlls/windows.ui/tests/uisettings.c @@ -49,12 +49,22 @@ static void check_interface_( unsigned int line, void *obj, const IID *iid, BOOL IUnknown_Release( unk ); }
+static void reset_color( Color *value ) +{ + value->A = 1; + value->R = 1; + value->G = 1; + value->B = 1; +} + static void test_UISettings_Statics(void) { static const WCHAR *uisettings_name = L"Windows.UI.ViewManagement.UISettings"; IUISettings3 *uisettings_statics3; IActivationFactory *factory; IInspectable *inspectable; + UIColorType type; + Color value; HSTRING str; HRESULT hr; LONG ref; @@ -86,6 +96,18 @@ static void test_UISettings_Statics(void) goto skip_uisettings_statics3; }
+ reset_color(&value); + type = UIColorType_Foreground; + hr = IUISettings3_GetColorValue( uisettings_statics3, type, &value ); + ok( hr == S_OK, "GetColorValue returned %#lx\n", hr ); + ok( value.A == 0 && value.R == 0 && value.G == 0 && value.B == 0, "got unexpected value.A == %d value.R == %d value.G == %d value.B == %d\n", value.A, value.R, value.G, value.B ); + + reset_color(&value); + type = UIColorType_Background; + hr = IUISettings3_GetColorValue( uisettings_statics3, type, &value ); + ok( hr == S_OK, "GetColorValue returned %#lx\n", hr ); + ok( value.A == 0 && value.R == 255 && value.G == 255 && value.B == 255, "got unexpected value.A == %d value.R == %d value.G == %d value.B == %d\n", value.A, value.R, value.G, value.B ); + IUISettings3_Release( uisettings_statics3 );
skip_uisettings_statics3:
Also, not sure if a dark mode checkbox should be added or if dark mode should be automatically set based on the loaded theme in Wine. Though, for the latter there needs to be a property that returns the mode of the theme. Name alone might not be sufficient.
I understand it's not entirely relevant to this MR, but have you considered implementing support for the `org.freedesktop.appearance.color-scheme` specification? It's used by GNOME, KDE, elementary, Firefox/Thunderbird, and Telegram Desktop so far. Probably others I didn't mention as well.
Relevant links: - GNOME blog post: https://blogs.gnome.org/alexm/2021/10/04/dark-style-preference/ - Spec: https://github.com/flatpak/xdg-desktop-portal/blob/d7a304a00697d7d608821253c... - KDE initial implementation: https://invent.kde.org/plasma/xdg-desktop-portal-kde/-/merge_requests/49 - KDE proper implementation: https://invent.kde.org/plasma/xdg-desktop-portal-kde/-/merge_requests/52
On Fri Feb 3 20:16:19 2023 +0000, Newbyte wrote:
Also, not sure if a dark mode checkbox should be added or if dark mode
should be automatically set based on the loaded theme in Wine. Though, for the latter there needs to be a property that returns the mode of the theme. Name alone might not be sufficient. I understand it's not entirely relevant to this MR, but have you considered implementing support for the `org.freedesktop.appearance.color-scheme` specification? It's used by GNOME, KDE, elementary, Firefox/Thunderbird, and Telegram Desktop so far. Probably others I didn't mention as well. Relevant links:
- GNOME blog post: https://blogs.gnome.org/alexm/2021/10/04/dark-style-preference/
- Spec: https://github.com/flatpak/xdg-desktop-portal/blob/d7a304a00697d7d608821253c...
- KDE initial implementation: https://invent.kde.org/plasma/xdg-desktop-portal-kde/-/merge_requests/49
- KDE proper implementation: https://invent.kde.org/plasma/xdg-desktop-portal-kde/-/merge_requests/52
I would like such an implementation as well, but that would require finding a way to move dbus out of mountmgr, and once this is done, it would allow for many other cool features in wine (bluetooth potentially, I have a proof of concept) along with this MR
On Fri Feb 3 20:17:22 2023 +0000, Etaash Mathamsetty wrote:
I would like such an implementation as well, but that would require finding a way to move dbus out of mountmgr, and once this is done, it would allow for many other cool features in wine (bluetooth potentially, I have a proof of concept) along with this MR
I think implementing `org.freedesktop.appearance.color-scheme` is out of scope of this PR
But this is definitely something I'll be looking for, I like being able to choose between system, light, or dark color schemes. In my mind system color scheme would just update `AppsUseLightTheme` registry key to match what the desktop environment expect. I also think such code should be placed in wineboot as it already modify the registry based on the return of unix calls.
On Sat Feb 4 17:48:18 2023 +0000, Loïc Rebmeister wrote:
I think implementing `org.freedesktop.appearance.color-scheme` is out of scope of this PR But this is definitely something I'll be looking for, I like being able to choose between system, light, or dark color schemes. In my mind system color scheme would just update `AppsUseLightTheme` registry key to match what the desktop environment expect. I also think such code should be placed in wineboot as it already modify the registry based on the return of unix calls.
yeah the dbus api is out of scope for this MR for sure.
On Sun Feb 5 04:33:03 2023 +0000, Etaash Mathamsetty wrote:
yeah the dbus api is out of scope for this MR for sure.
I haven't looked into it much but `org.freedesktop.appearance.color-scheme` definitely seems useful.
At the moment, I think adding in a checkbox in `winecfg` should be sufficient.