cui/source/options/optgdlg.cxx                             |   33 +++-
 cui/source/options/optgdlg.hxx                             |    2 
 cui/uiconfig/ui/optviewpage.ui                             |  106 ++++++++++---
 include/vcl/settings.hxx                                   |    3 
 officecfg/registry/schema/org/openoffice/Office/Common.xcs |   25 +++
 vcl/inc/osx/salframe.h                                     |    1 
 vcl/inc/salframe.hxx                                       |    2 
 vcl/inc/unx/gtk/gtkframe.hxx                               |    1 
 vcl/inc/win/salframe.h                                     |    1 
 vcl/osx/salframe.cxx                                       |   28 ++-
 vcl/source/app/settings.cxx                                |   20 ++
 vcl/unx/gtk3/gtkframe.cxx                                  |   48 ++++-
 vcl/win/gdi/salnativewidgets-luna.cxx                      |   49 +++---
 vcl/win/window/salframe.cxx                                |   51 +++++-
 14 files changed, 308 insertions(+), 62 deletions(-)

New commits:
commit 37b34c1ad1cb5dad2f7cc38911a901ed4edb75cf
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Mon Feb 6 20:53:55 2023 +0000
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Tue Apr 11 13:39:11 2023 +0200

    tdf#153229 add a switch to override honoring system dark mode
    
    Change-Id: Iafb6182e05dc65d20d0809476ee58908f7426d39
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146597
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    (cherry picked from commit f7c03364e24da285ea95cea0cc688a7a120fc163)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146745
    Reviewed-by: Sophie Gautier <so...@libreoffice.org>
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    (cherry picked from commit f0814dca8f05f524068b8217a9f1eabd8266cdc4)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147056
    Reviewed-by: Christian Lohmaier <lohmaier+libreoff...@googlemail.com>
    Tested-by: Adolfo Jayme Barrientos <fit...@ubuntu.com>
    Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150228
    Tested-by: Mike Kaganski <mike.kagan...@collabora.com>
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/cui/source/options/optgdlg.cxx b/cui/source/options/optgdlg.cxx
index 4405fdb3e76b..5663d3912488 100644
--- a/cui/source/options/optgdlg.cxx
+++ b/cui/source/options/optgdlg.cxx
@@ -528,6 +528,8 @@ OfaViewTabPage::OfaViewTabPage(weld::Container* pPage, 
weld::DialogController* p
     , m_xIconSizeLB(m_xBuilder->weld_combo_box("iconsize"))
     , m_xSidebarIconSizeLB(m_xBuilder->weld_combo_box("sidebariconsize"))
     , 
m_xNotebookbarIconSizeLB(m_xBuilder->weld_combo_box("notebookbariconsize"))
+    , m_xDarkModeFrame(m_xBuilder->weld_widget("darkmode"))
+    , m_xAppearanceStyleLB(m_xBuilder->weld_combo_box("appearance"))
     , m_xIconStyleLB(m_xBuilder->weld_combo_box("iconstyle"))
     , m_xFontAntiAliasing(m_xBuilder->weld_check_button("aafont"))
     , m_xAAPointLimitLabel(m_xBuilder->weld_label("aafrom"))
@@ -547,9 +549,14 @@ OfaViewTabPage::OfaViewTabPage(weld::Container* pPage, 
weld::DialogController* p
     , m_xMoreIcons(m_xBuilder->weld_button("btnMoreIcons"))
     , m_xRunGPTests(m_xBuilder->weld_button("btn_rungptest"))
 {
-    if (Application::GetToolkitName().startsWith("gtk"))
+    OUString sToolKitName(Application::GetToolkitName());
+    if (sToolKitName.startsWith("gtk"))
         m_xMenuIconBox->hide();
 
+    const bool bHasDarkMode = sToolKitName.startsWith("gtk") || sToolKitName 
== "osx" || sToolKitName == "win";
+    if (!bHasDarkMode)
+        m_xDarkModeFrame->hide();
+
     m_xFontAntiAliasing->connect_toggled( LINK( this, OfaViewTabPage, 
OnAntialiasingToggled ) );
 
     m_xUseSkia->connect_toggled(LINK(this, OfaViewTabPage, OnUseSkiaToggled));
@@ -668,6 +675,7 @@ bool OfaViewTabPage::FillItemSet( SfxItemSet* )
 {
     bool bModified = false;
     bool bMenuOptModified = false;
+    bool bDarkModeOptModified = false;
     bool bRepaintWindows(false);
     std::shared_ptr<comphelper::ConfigurationChanges> 
xChanges(comphelper::ConfigurationChanges::create());
 
@@ -781,6 +789,12 @@ bool OfaViewTabPage::FillItemSet( SfxItemSet* )
         bAppearanceChanged = true;
     }
 
+    if (m_xAppearanceStyleLB->get_value_changed_from_saved())
+    {
+        bDarkModeOptModified = true;
+        bModified = true;
+    }
+
     if (m_xContextMenuShortcutsLB->get_value_changed_from_saved())
     {
         officecfg::Office::Common::View::Menu::ShortcutsInContextMenus::set(
@@ -824,12 +838,20 @@ bool OfaViewTabPage::FillItemSet( SfxItemSet* )
 
     xChanges->commit();
 
-    if( bMenuOptModified )
+    if (bMenuOptModified || bDarkModeOptModified)
     {
         // Set changed settings to the application instance
         AllSettings aAllSettings = Application::GetSettings();
-        StyleSettings aStyleSettings = aAllSettings.GetStyleSettings();
-        aAllSettings.SetStyleSettings(aStyleSettings);
+
+        if (bMenuOptModified)
+        {
+            StyleSettings aStyleSettings = aAllSettings.GetStyleSettings();
+            aAllSettings.SetStyleSettings(aStyleSettings);
+        }
+
+        if (bDarkModeOptModified)
+            MiscSettings::SetDarkMode(m_xAppearanceStyleLB->get_active());
+
         Application::MergeSystemSettings( aAllSettings );
         Application::SetSettings(aAllSettings);
     }
@@ -912,6 +934,9 @@ void OfaViewTabPage::Reset( const SfxItemSet* )
     m_xIconStyleLB->set_active(nStyleLB_InitialSelection);
     m_xIconStyleLB->save_value();
 
+    
m_xAppearanceStyleLB->set_active(officecfg::Office::Common::Misc::Appearance::get());
+    m_xAppearanceStyleLB->save_value();
+
     // Mouse Snap
     
m_xMousePosLB->set_active(static_cast<sal_Int32>(pAppearanceCfg->GetSnapMode()));
     m_xMousePosLB->save_value();
diff --git a/cui/source/options/optgdlg.hxx b/cui/source/options/optgdlg.hxx
index a4c686cc2b27..870e3f39bccc 100644
--- a/cui/source/options/optgdlg.hxx
+++ b/cui/source/options/optgdlg.hxx
@@ -87,6 +87,8 @@ private:
     std::unique_ptr<weld::ComboBox> m_xIconSizeLB;
     std::unique_ptr<weld::ComboBox> m_xSidebarIconSizeLB;
     std::unique_ptr<weld::ComboBox> m_xNotebookbarIconSizeLB;
+    std::unique_ptr<weld::Widget> m_xDarkModeFrame;
+    std::unique_ptr<weld::ComboBox> m_xAppearanceStyleLB;
     std::unique_ptr<weld::ComboBox> m_xIconStyleLB;
 
     std::unique_ptr<weld::CheckButton> m_xFontAntiAliasing;
diff --git a/cui/uiconfig/ui/optviewpage.ui b/cui/uiconfig/ui/optviewpage.ui
index ac6b7fcde239..a371f83e584a 100644
--- a/cui/uiconfig/ui/optviewpage.ui
+++ b/cui/uiconfig/ui/optviewpage.ui
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.38.2 -->
+<!-- Generated with glade 3.40.0 -->
 <interface domain="cui">
   <requires lib="gtk+" version="3.20"/>
   <object class="GtkAdjustment" id="adjustment2">
@@ -18,7 +18,7 @@
     <property name="border-width">6</property>
     <property name="column-spacing">24</property>
     <child>
-      <!-- n-columns=1 n-rows=4 -->
+      <!-- n-columns=1 n-rows=5 -->
       <object class="GtkGrid" id="grid2">
         <property name="visible">True</property>
         <property name="can-focus">False</property>
@@ -126,7 +126,7 @@
           </object>
           <packing>
             <property name="left-attach">0</property>
-            <property name="top-attach">3</property>
+            <property name="top-attach">4</property>
           </packing>
         </child>
         <child>
@@ -249,7 +249,7 @@
           </object>
           <packing>
             <property name="left-attach">0</property>
-            <property name="top-attach">2</property>
+            <property name="top-attach">3</property>
           </packing>
         </child>
         <child>
@@ -390,7 +390,7 @@
           </object>
           <packing>
             <property name="left-attach">0</property>
-            <property name="top-attach">1</property>
+            <property name="top-attach">2</property>
           </packing>
         </child>
         <child>
@@ -472,6 +472,76 @@
               </object>
             </child>
           </object>
+          <packing>
+            <property name="left-attach">0</property>
+            <property name="top-attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkFrame" id="darkmode">
+            <property name="visible">True</property>
+            <property name="can-focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="label-xalign">0</property>
+            <property name="shadow-type">none</property>
+            <child>
+              <!-- n-columns=2 n-rows=1 -->
+              <object class="GtkGrid" id="refgrid2">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <property name="margin-start">12</property>
+                <property name="margin-top">6</property>
+                <property name="hexpand">True</property>
+                <property name="column-spacing">6</property>
+                <child>
+                  <object class="GtkComboBoxText" id="appearance">
+                    <property name="visible">True</property>
+                    <property name="can-focus">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="active">0</property>
+                    <items>
+                      <item translatable="yes" 
context="optviewpage|appearance">System</item>
+                      <item translatable="yes" 
context="optviewpage|appearance">Light</item>
+                      <item translatable="yes" 
context="optviewpage|appearance">Dark</item>
+                    </items>
+                    <child internal-child="accessible">
+                      <object class="AtkObject" id="appearance-atkobject">
+                        <property name="AtkObject::accessible-description" 
translatable="yes" context="extended_tip | appearance">Specifies whether to 
follow the system appearance mode or override Dark or Light.</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left-attach">1</property>
+                    <property name="top-attach">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label7">
+                    <property name="visible">True</property>
+                    <property name="can-focus">False</property>
+                    <property name="label" translatable="yes" 
context="optviewpage|label7">Mode:</property>
+                    <property name="use-underline">True</property>
+                    <property name="mnemonic-widget">appearance</property>
+                    <property name="xalign">0</property>
+                  </object>
+                  <packing>
+                    <property name="left-attach">0</property>
+                    <property name="top-attach">0</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+            <child type="label">
+              <object class="GtkLabel" id="label16">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <property name="label" translatable="yes" 
context="optviewpage|label16">Appearance</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                </attributes>
+              </object>
+            </child>
+          </object>
           <packing>
             <property name="left-attach">0</property>
             <property name="top-attach">0</property>
@@ -757,26 +827,28 @@
   </object>
   <object class="GtkSizeGroup" id="sizegroupLabel">
     <widgets>
-      <widget name="label6"/>
-      <widget name="label14"/>
-      <widget name="label8"/>
-      <widget name="label9"/>
-      <widget name="label13"/>
-      <widget name="label10"/>
       <widget name="label11"/>
       <widget name="label12"/>
+      <widget name="label13"/>
+      <widget name="label10"/>
+      <widget name="label8"/>
+      <widget name="label9"/>
+      <widget name="label14"/>
+      <widget name="label6"/>
+      <widget name="label7"/>
     </widgets>
   </object>
   <object class="GtkSizeGroup" id="sizegroupWidget">
     <widgets>
-      <widget name="iconstyle"/>
-      <widget name="iconsize"/>
-      <widget name="notebookbariconsize"/>
-      <widget name="sidebariconsize"/>
-      <widget name="menuicons"/>
-      <widget name="contextmenushortcuts"/>
       <widget name="mousepos"/>
       <widget name="mousemiddle"/>
+      <widget name="menuicons"/>
+      <widget name="contextmenushortcuts"/>
+      <widget name="notebookbariconsize"/>
+      <widget name="sidebariconsize"/>
+      <widget name="iconsize"/>
+      <widget name="iconstyle"/>
+      <widget name="appearance"/>
     </widgets>
   </object>
 </interface>
diff --git a/include/vcl/settings.hxx b/include/vcl/settings.hxx
index 9d865544bd51..de6a4b903c07 100644
--- a/include/vcl/settings.hxx
+++ b/include/vcl/settings.hxx
@@ -645,6 +645,9 @@ public:
     bool                            GetDisablePrinting() const;
     void                            SetEnableLocalizedDecimalSep( bool bEnable 
);
     bool                            GetEnableLocalizedDecimalSep() const;
+    // 0 auto, 1 light, 2, dark
+    static void                     SetDarkMode(int nMode);
+    static int                      GetDarkMode();
 
     bool                            operator ==( const MiscSettings& rSet ) 
const;
     bool                            operator !=( const MiscSettings& rSet ) 
const;
diff --git a/officecfg/registry/schema/org/openoffice/Office/Common.xcs 
b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
index ea175aabf532..24716e1992d8 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Common.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
@@ -5416,6 +5416,31 @@
       <info>
         <desc>Determines the miscellaneous entries for the common group.</desc>
       </info>
+      <prop oor:name="Appearance" oor:type="xs:short" oor:nillable="false">
+        <!-- UIHints: Tools  Options - General  View  [Section] Appearance -->
+        <info>
+          <desc>Specifies the appearance of the user interface.</desc>
+          <label>Appearance</label>
+        </info>
+        <constraints>
+          <enumeration oor:value="0">
+            <info>
+              <desc>Automatic, from system settings</desc>
+            </info>
+          </enumeration>
+          <enumeration oor:value="1">
+            <info>
+              <desc>Light</desc>
+            </info>
+          </enumeration>
+          <enumeration oor:value="2">
+            <info>
+              <desc>Dark</desc>
+            </info>
+          </enumeration>
+        </constraints>
+        <value>0</value>
+      </prop>
       <prop oor:name="MaxOpenDocuments" oor:type="xs:int">
         <info>
           <desc>Determines the maximum count of documents, which are allowed to
diff --git a/vcl/inc/osx/salframe.h b/vcl/inc/osx/salframe.h
index 71b8eb45b772..af8783b96147 100644
--- a/vcl/inc/osx/salframe.h
+++ b/vcl/inc/osx/salframe.h
@@ -163,6 +163,7 @@ public:
         tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long 
nHeight ) override;
     // done setting up the clipregion
     virtual void EndSetClipRegion() override;
+    virtual void UpdateDarkMode() override;
 
     void UpdateFrameGeometry();
 
diff --git a/vcl/inc/salframe.hxx b/vcl/inc/salframe.hxx
index 552d88eb2519..a78f9afe08c0 100644
--- a/vcl/inc/salframe.hxx
+++ b/vcl/inc/salframe.hxx
@@ -299,6 +299,8 @@ public:
     void SetModalHierarchyHdl(const Link<bool, void>& rLink) { 
m_aModalHierarchyHdl = rLink; }
     void NotifyModalHierarchy(bool bModal) { 
m_aModalHierarchyHdl.Call(bModal); }
 
+    virtual void            UpdateDarkMode() {}
+
     // Call the callback set; this sometimes necessary for implementation 
classes
     // that should not know more than necessary about the SalFrame 
implementation
     // (e.g. input methods, printer update handlers).
diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx
index 5b2df74d3f5c..bd5f4ded12d5 100644
--- a/vcl/inc/unx/gtk/gtkframe.hxx
+++ b/vcl/inc/unx/gtk/gtkframe.hxx
@@ -611,6 +611,7 @@ public:
     virtual bool                UpdatePopover(void* nId, const OUString& 
rHelpText, vcl::Window* pParent, const tools::Rectangle& rHelpArea) override;
     virtual bool                HidePopover(void* nId) override;
     virtual weld::Window*       GetFrameWeld() const override;
+    virtual void                UpdateDarkMode() override;
 
     static GtkSalFrame         *getFromWindow( GtkWidget *pWindow );
 
diff --git a/vcl/inc/win/salframe.h b/vcl/inc/win/salframe.h
index dedac6906467..78f61945a311 100644
--- a/vcl/inc/win/salframe.h
+++ b/vcl/inc/win/salframe.h
@@ -139,6 +139,7 @@ public:
     virtual void                BeginSetClipRegion( sal_uInt32 nRects ) 
override;
     virtual void                UnionClipRegion( tools::Long nX, tools::Long 
nY, tools::Long nWidth, tools::Long nHeight ) override;
     virtual void                EndSetClipRegion() override;
+    virtual void                UpdateDarkMode() override;
 
     constexpr vcl::WindowState state() const { return m_eState; }
     void UpdateFrameState();
diff --git a/vcl/osx/salframe.cxx b/vcl/osx/salframe.cxx
index 02a3879648db..bf2257be9fac 100644
--- a/vcl/osx/salframe.cxx
+++ b/vcl/osx/salframe.cxx
@@ -1258,6 +1258,26 @@ void AquaSalFrame::getResolution( sal_Int32& o_rDPIX, 
sal_Int32& o_rDPIY )
     mpGraphics->GetResolution( o_rDPIX, o_rDPIY );
 }
 
+void AquaSalFrame::UpdateDarkMode()
+{
+    if (@available(macOS 10.14, iOS 13, *))
+    {
+        switch (MiscSettings::GetDarkMode())
+        {
+            case 0: // auto
+            default:
+                [NSApp setAppearance: nil];
+                break;
+            case 1: // light
+                [NSApp setAppearance: [NSAppearance appearanceNamed: 
NSAppearanceNameAqua]];
+                break;
+            case 2: // dark
+                [NSApp setAppearance: [NSAppearance appearanceNamed: 
NSAppearanceNameDarkAqua]];
+                break;
+        }
+    }
+}
+
 // on OSX-Aqua the style settings are independent of the frame, so it does
 // not really belong here. Since the connection to the Appearance_Manager
 // is currently done in salnativewidgets.cxx this would be a good place.
@@ -1289,11 +1309,11 @@ SAL_WNODEPRECATED_DECLARATIONS_POP
     StyleSettings aStyleSettings = rSettings.GetStyleSettings();
 
     bool bUseDarkMode(false);
-    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
-    if (userDefaults != nil)
+    if (@available(macOS 10.14, iOS 13, *))
     {
-        NSString* setting = [userDefaults stringForKey: 
@"AppleInterfaceStyle"];
-        bUseDarkMode = (setting && [setting isEqual: @"Dark"]);
+        NSAppearanceName match = [mpNSView.effectiveAppearance 
bestMatchFromAppearancesWithNames: @[
+                                  NSAppearanceNameAqua, 
NSAppearanceNameDarkAqua]];
+        bUseDarkMode = [match isEqualToString: NSAppearanceNameDarkAqua];
     }
     // there is no sukapura_dark, at the time of writing at least, so whatever
     // is considered the default dark icon set will be used
diff --git a/vcl/source/app/settings.cxx b/vcl/source/app/settings.cxx
index c12a520ae025..9762c2164f92 100644
--- a/vcl/source/app/settings.cxx
+++ b/vcl/source/app/settings.cxx
@@ -53,6 +53,7 @@
 
 using namespace ::com::sun::star;
 
+#include <salframe.hxx>
 #include <svdata.hxx>
 
 struct ImplMouseData
@@ -2755,6 +2756,25 @@ bool MiscSettings::GetEnableLocalizedDecimalSep() const
     return mxData->mbEnableLocalizedDecimalSep;
 }
 
+int MiscSettings::GetDarkMode()
+{
+    return officecfg::Office::Common::Misc::Appearance::get();
+}
+
+void MiscSettings::SetDarkMode(int nMode)
+{
+    std::shared_ptr<comphelper::ConfigurationChanges> 
batch(comphelper::ConfigurationChanges::create());
+    officecfg::Office::Common::Misc::Appearance::set(nMode, batch);
+    batch->commit();
+
+    vcl::Window *pWin = Application::GetFirstTopLevelWindow();
+    while (pWin)
+    {
+        pWin->ImplGetFrame()->UpdateDarkMode();
+        pWin = Application::GetNextTopLevelWindow(pWin);
+    }
+}
+
 HelpSettings::HelpSettings()
     : mxData(std::make_shared<ImplHelpData>())
 {
diff --git a/vcl/unx/gtk3/gtkframe.cxx b/vcl/unx/gtk3/gtkframe.cxx
index 1d72e46ff21a..69dc11b7ea44 100644
--- a/vcl/unx/gtk3/gtkframe.cxx
+++ b/vcl/unx/gtk3/gtkframe.cxx
@@ -45,6 +45,7 @@
 #include <window.h>
 
 #include <basegfx/vector/b2ivector.hxx>
+#include <officecfg/Office/Common.hxx>
 
 #include <dlfcn.h>
 
@@ -1315,20 +1316,20 @@ namespace
         PREFER_LIGHT
     };
 
-    bool ReadColorScheme(GDBusProxy* proxy, GVariant** out)
+    void ReadColorScheme(GDBusProxy* proxy, GVariant** out)
     {
         g_autoptr (GVariant) ret =
             g_dbus_proxy_call_sync(proxy, "Read",
                                    g_variant_new ("(ss)", 
"org.freedesktop.appearance", "color-scheme"),
                                    G_DBUS_CALL_FLAGS_NONE, G_MAXINT, nullptr, 
nullptr);
         if (!ret)
-            return false;
+            return;
 
         g_autoptr (GVariant) child = nullptr;
         g_variant_get(ret, "(v)", &child);
         g_variant_get(child, "v", out);
 
-        return true;
+        return;
     }
 }
 
@@ -1337,9 +1338,30 @@ void GtkSalFrame::SetColorScheme(GVariant* variant)
     if (!m_pWindow)
         return;
 
-    guint32 color_scheme = g_variant_get_uint32(variant);
-    if (color_scheme > PREFER_LIGHT)
-        color_scheme = DEFAULT;
+    guint32 color_scheme;
+
+    switch (officecfg::Office::Common::Misc::Appearance::get())
+    {
+        default:
+        case 0: // Auto
+        {
+            if (variant)
+            {
+                color_scheme = g_variant_get_uint32(variant);
+                if (color_scheme > PREFER_LIGHT)
+                    color_scheme = DEFAULT;
+            }
+            else
+                color_scheme = DEFAULT;
+            break;
+        }
+        case 1: // Light
+            color_scheme = PREFER_LIGHT;
+            break;
+        case 2: // Dark
+            color_scheme = PREFER_DARK;
+            break;
+    }
 
     bool bDarkIconTheme(color_scheme == PREFER_DARK);
     GtkSettings* pSettings = gtk_widget_get_settings(m_pWindow);
@@ -1380,16 +1402,18 @@ void GtkSalFrame::ListenPortalSettings()
                                               
"org.freedesktop.portal.Settings",
                                               nullptr,
                                               nullptr);
-    if (!m_pSettingsPortal)
-        return;
 
-    g_autoptr (GVariant) value = nullptr;
+    UpdateDarkMode();
 
-    if (!ReadColorScheme(m_pSettingsPortal, &value))
-        return;
+    m_nPortalSettingChangedSignalId = g_signal_connect(m_pSettingsPortal, 
"g-signal", G_CALLBACK(settings_portal_changed_cb), this);
+}
 
+void GtkSalFrame::UpdateDarkMode()
+{
+    g_autoptr (GVariant) value = nullptr;
+    if (m_pSettingsPortal)
+        ReadColorScheme(m_pSettingsPortal, &value);
     SetColorScheme(value);
-    m_nPortalSettingChangedSignalId = g_signal_connect(m_pSettingsPortal, 
"g-signal", G_CALLBACK(settings_portal_changed_cb), this);
 }
 
 #if GTK_CHECK_VERSION(4,0,0)
diff --git a/vcl/win/gdi/salnativewidgets-luna.cxx 
b/vcl/win/gdi/salnativewidgets-luna.cxx
index 1cd6245658d6..c837cb7a1c82 100644
--- a/vcl/win/gdi/salnativewidgets-luna.cxx
+++ b/vcl/win/gdi/salnativewidgets-luna.cxx
@@ -402,16 +402,30 @@ bool UseDarkMode()
     if (!bOSSupportsDarkMode)
         return false;
 
-    HINSTANCE hUxthemeLib = LoadLibraryExW(L"uxtheme.dll", nullptr, 
LOAD_LIBRARY_SEARCH_SYSTEM32);
-    if (!hUxthemeLib)
-        return false;
+    bool bRet(false);
+    switch (MiscSettings::GetDarkMode())
+    {
+        case 0: // auto
+        default:
+        {
+            HINSTANCE hUxthemeLib = LoadLibraryExW(L"uxtheme.dll", nullptr, 
LOAD_LIBRARY_SEARCH_SYSTEM32);
+            if (!hUxthemeLib)
+                return false;
 
-    bool bRet = false;
-    typedef bool(WINAPI* ShouldAppsUseDarkMode_t)();
-    if (auto ShouldAppsUseDarkMode = 
reinterpret_cast<ShouldAppsUseDarkMode_t>(GetProcAddress(hUxthemeLib, 
MAKEINTRESOURCEA(132))))
-        bRet = ShouldAppsUseDarkMode();
+            typedef bool(WINAPI* ShouldAppsUseDarkMode_t)();
+            if (auto ShouldAppsUseDarkMode = 
reinterpret_cast<ShouldAppsUseDarkMode_t>(GetProcAddress(hUxthemeLib, 
MAKEINTRESOURCEA(132))))
+                bRet = ShouldAppsUseDarkMode();
 
-    FreeLibrary(hUxthemeLib);
+            FreeLibrary(hUxthemeLib);
+            break;
+        }
+        case 1: // light
+            bRet = false;
+            break;
+        case 2: // dark
+            bRet = true;
+            break;
+    }
 
     return bRet;
 }
@@ -421,7 +435,8 @@ static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, 
RECT rc,
                             ControlPart nPart,
                             ControlState nState,
                             const ImplControlValue& aValue,
-                            OUString const & aCaption )
+                            OUString const & aCaption,
+                            bool bUseDarkMode )
 {
     // a listbox dropdown is actually a combobox dropdown
     if( nType == ControlType::Listbox )
@@ -767,7 +782,7 @@ static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, 
RECT rc,
     {
         // tabpane in tabcontrols gets drawn in "darkmode" as if it was a
         // a "light" theme, so bodge this by drawing a frame directly
-        if (UseDarkMode())
+        if (bUseDarkMode)
         {
             Color 
aColor(Application::GetSettings().GetStyleSettings().GetDisableColor());
             ScopedHBRUSH hbrush(CreateSolidBrush(RGB(aColor.GetRed(),
@@ -783,7 +798,7 @@ static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, 
RECT rc,
     if( nType == ControlType::TabBody )
     {
         // tabbody in main window gets drawn in white in "darkmode", so bodge 
this here
-        if (UseDarkMode())
+        if (bUseDarkMode)
         {
             Color 
aColor(Application::GetSettings().GetStyleSettings().GetWindowColor());
             ScopedHBRUSH hbrush(CreateSolidBrush(RGB(aColor.GetRed(),
@@ -843,7 +858,7 @@ static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, 
RECT rc,
 
         // tabitem in tabcontrols gets drawn in "darkmode" as if it was a
         // a "light" theme, so bodge this by drawing with a button instead
-        if (UseDarkMode())
+        if (bUseDarkMode)
         {
             Color aColor;
             if (iState == TILES_SELECTED)
@@ -911,7 +926,7 @@ static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, 
RECT rc,
             }
 
             // toolbar in main window gets drawn in white in "darkmode", so 
bodge this here
-            if (UseDarkMode())
+            if (bUseDarkMode)
             {
                 Color 
aColor(Application::GetSettings().GetStyleSettings().GetWindowColor());
                 ScopedHBRUSH hbrush(CreateSolidBrush(RGB(aColor.GetRed(),
@@ -943,7 +958,7 @@ static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, 
RECT rc,
                 rc.bottom += pValue->maTopDockingAreaHeight;    // extend 
potential gradient to cover docking area as well
 
                 // menubar in main window gets drawn in white in "darkmode", 
so bodge this here
-                if (UseDarkMode())
+                if (bUseDarkMode)
                 {
                     Color 
aColor(Application::GetSettings().GetStyleSettings().GetWindowColor());
                     ScopedHBRUSH hbrush(CreateSolidBrush(RGB(aColor.GetRed(),
@@ -1302,7 +1317,7 @@ bool WinSalGraphics::drawNativeControl( ControlType nType,
         // set default text alignment
         int ta = SetTextAlign(getHDC(), TA_LEFT|TA_TOP|TA_NOUPDATECP);
 
-        bOk = ImplDrawNativeControl(getHDC(), hTheme, rc, nType, nPart, 
nState, aValue, aCaptionStr);
+        bOk = ImplDrawNativeControl(getHDC(), hTheme, rc, nType, nPart, 
nState, aValue, aCaptionStr, bUseDarkMode);
 
         // restore alignment
         SetTextAlign(getHDC(), ta);
@@ -1318,8 +1333,8 @@ bool WinSalGraphics::drawNativeControl( ControlType nType,
         SetTextAlign(aWhiteDC->getCompatibleHDC(), 
TA_LEFT|TA_TOP|TA_NOUPDATECP);
         aWhiteDC->fill(RGB(0xff, 0xff, 0xff));
 
-        if (ImplDrawNativeControl(aBlackDC->getCompatibleHDC(), hTheme, rc, 
nType, nPart, nState, aValue, aCaptionStr) &&
-            ImplDrawNativeControl(aWhiteDC->getCompatibleHDC(), hTheme, rc, 
nType, nPart, nState, aValue, aCaptionStr))
+        if (ImplDrawNativeControl(aBlackDC->getCompatibleHDC(), hTheme, rc, 
nType, nPart, nState, aValue, aCaptionStr, bUseDarkMode) &&
+            ImplDrawNativeControl(aWhiteDC->getCompatibleHDC(), hTheme, rc, 
nType, nPart, nState, aValue, aCaptionStr, bUseDarkMode))
         {
             bOk = pImpl->RenderAndCacheNativeControl(*aWhiteDC, *aBlackDC, 
cacheRect.Left(), cacheRect.Top(), aControlCacheKey);
         }
diff --git a/vcl/win/window/salframe.cxx b/vcl/win/window/salframe.cxx
index dc804a76ab35..73842a792754 100644
--- a/vcl/win/window/salframe.cxx
+++ b/vcl/win/window/salframe.cxx
@@ -261,6 +261,17 @@ void ImplSalGetWorkArea( HWND hWnd, RECT *pRect, const 
RECT *pParentRect )
     }
 }
 
+namespace {
+
+enum PreferredAppMode
+{
+    AllowDark = 1,
+    ForceDark = 2,
+    ForceLight = 3
+};
+
+}
+
 static void UpdateDarkMode(HWND hWnd)
 {
     static bool bOSSupportsDarkMode = OSSupportsDarkMode();
@@ -271,18 +282,37 @@ static void UpdateDarkMode(HWND hWnd)
     if (!hUxthemeLib)
         return;
 
-    typedef void(WINAPI* AllowDarkModeForWindow_t)(HWND, BOOL);
-    if (auto AllowDarkModeForWindow = 
reinterpret_cast<AllowDarkModeForWindow_t>(GetProcAddress(hUxthemeLib, 
MAKEINTRESOURCEA(133))))
-        AllowDarkModeForWindow(hWnd, TRUE);
-
-    typedef bool(WINAPI* ShouldAppsUseDarkMode_t)();
-    if (auto ShouldAppsUseDarkMode = 
reinterpret_cast<ShouldAppsUseDarkMode_t>(GetProcAddress(hUxthemeLib, 
MAKEINTRESOURCEA(132))))
+    typedef PreferredAppMode(WINAPI* SetPreferredAppMode_t)(PreferredAppMode);
+    auto SetPreferredAppMode = 
reinterpret_cast<SetPreferredAppMode_t>(GetProcAddress(hUxthemeLib, 
MAKEINTRESOURCEA(135)));
+    if (SetPreferredAppMode)
     {
-        BOOL bDarkMode = ShouldAppsUseDarkMode();
-        DwmSetWindowAttribute(hWnd, 20, &bDarkMode, sizeof(bDarkMode));
+        switch (MiscSettings::GetDarkMode())
+        {
+            case 0:
+                SetPreferredAppMode(AllowDark);
+                break;
+            case 1:
+                SetPreferredAppMode(ForceLight);
+                break;
+            case 2:
+                SetPreferredAppMode(ForceDark);
+                break;
+        }
     }
 
+    BOOL bDarkMode = UseDarkMode();
+
+    typedef void(WINAPI* AllowDarkModeForWindow_t)(HWND, BOOL);
+    auto AllowDarkModeForWindow = 
reinterpret_cast<AllowDarkModeForWindow_t>(GetProcAddress(hUxthemeLib, 
MAKEINTRESOURCEA(133)));
+    if (AllowDarkModeForWindow)
+        AllowDarkModeForWindow(hWnd, bDarkMode);
+
     FreeLibrary(hUxthemeLib);
+
+    if (!AllowDarkModeForWindow)
+        return;
+
+    DwmSetWindowAttribute(hWnd, 20, &bDarkMode, sizeof(bDarkMode));
 }
 
 SalFrame* ImplSalCreateFrame( WinSalInstance* pInst,
@@ -3061,6 +3091,11 @@ void WinSalFrame::EndSetClipRegion()
     }
 }
 
+void WinSalFrame::UpdateDarkMode()
+{
+    ::UpdateDarkMode(mhWnd);
+}
+
 static bool ImplHandleMouseMsg( HWND hWnd, UINT nMsg,
                                 WPARAM wParam, LPARAM lParam )
 {

Reply via email to