910e62b5创建于 1月15日历史提交
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gtk/os_settings_provider_gtk.h"

#include <glib-object.h>
#include <glib.h>

#include <string>

#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
#include "ui/base/glib/scoped_gsignal.h"
#include "ui/gfx/color_utils.h"
#include "ui/gtk/gtk_compat.h"
#include "ui/gtk/gtk_util.h"
#include "ui/native_theme/native_theme.h"

namespace gtk {

OsSettingsProviderGtk::OsSettingsProviderGtk()
    : OsSettingsProvider(PriorityLevel::kProduction) {}

OsSettingsProviderGtk::~OsSettingsProviderGtk() = default;

ui::NativeTheme::PreferredColorScheme
OsSettingsProviderGtk::PreferredColorScheme() const {
  // GTK has a dark mode setting called "gtk-application-prefer-dark-theme", but
  // this is really only used for themes that have a dark or light variant that
  // gets toggled based on this setting (eg. Adwaita).  Most dark themes do not
  // have a light variant and aren't affected by the setting.  Because of this,
  // experimentally check if the theme is dark by checking if the window
  // background color is dark.
  return color_utils::IsDark(GetBgColor({}))
             ? ui::NativeTheme::PreferredColorScheme::kDark
             : ui::NativeTheme::PreferredColorScheme::kLight;
}

ui::NativeTheme::PreferredContrast OsSettingsProviderGtk::PreferredContrast()
    const {
  // GTK doesn't have a native high contrast setting.  Rather, it's implied by
  // the theme name.  The only high contrast GTK themes that I know of are
  // HighContrast (GNOME) and ContrastHighInverse (MATE).  So infer the contrast
  // based on if the theme name contains both "high" and "contrast",
  // case-insensitive.
  const std::string theme_name =
      base::ToLowerASCII(GetGtkSettingsStringProperty(
          gtk_settings_get_default(), "gtk-theme-name"));
  const bool high_contrast = base::Contains(theme_name, "high") &&
                             base::Contains(theme_name, "contrast");
  return high_contrast ? ui::NativeTheme::PreferredContrast::kMore
                       : ui::NativeTheme::PreferredContrast::kNoPreference;
}

base::TimeDelta OsSettingsProviderGtk::CaretBlinkInterval() const {
  // Default value for `gtk-cursor-blink-time` from
  // https://docs.gtk.org/gtk3/property.Settings.gtk-cursor-blink-time.html.
  gint cursor_blink_time = 1200;
  gboolean cursor_blink = TRUE;
  g_object_get(gtk_settings_get_default(), "gtk-cursor-blink-time",
               &cursor_blink_time, "gtk-cursor-blink", &cursor_blink, nullptr);
  return cursor_blink ? base::Milliseconds(cursor_blink_time / 2)
                      : base::TimeDelta();
}

ScopedGSignal OsSettingsProviderGtk::ConnectSignal(const gchar* name) {
  return ScopedGSignal(gtk_settings_get_default(), name,
                       base::BindRepeating(&OsSettingsProviderGtk::OnSignal,
                                           base::Unretained(this)),
                       G_CONNECT_AFTER);
}

void OsSettingsProviderGtk::OnSignal(GtkSettings*, GtkParamSpec*) {
  NotifyOnSettingsChanged();
}

}  // namespace gtk