强制深色主题

GNOME 应用程序会尊重系统设置中的浅色或深色主题。但是,你可以在应用程序的 UI 中向用户提供强制深色主题的选择。

../../../_images/dark_mode.png

将“深色模式”项目添加到应用程序的菜单

  1. 打开 TextViewerWindow 部件的 UI 定义文件

  2. app.dark 操作添加一个菜单项,命名为 深色模式

<menu id="primary_menu">
  <section>
    <item>
      <attribute name="label" translatable="yes">Save _as...</attribute>
      <attribute name="action">win.save-as</attribute>
    </item>
    <item>
      <attribute name="label" translatable="yes">_Dark mode</attribute>
      <attribute name="action">app.dark-mode</attribute>
    </item>

将深色模式操作添加到应用程序

  1. 打开 TextViewApplication 源代码

  2. 找到 TextViewApplication 实例初始化函数

  3. 创建 dark-mode 状态操作,并连接到其 activatechange-state 信号

  4. 将操作添加到应用程序

static void
text_viewer_application_init (TextViewerApplication *self)
{
  g_autoptr (GSimpleAction) dark_action =
    g_simple_action_new_stateful ("dark-mode",
                                  NULL,
                                  g_variant_new_boolean (FALSE));
  g_signal_connect (dark_action, "activate", G_CALLBACK (toggle_dark_mode), self);
  g_signal_connect (dark_action, "change-state", G_CALLBACK (change_color_scheme), self);
  g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (dark_action));
  1. 添加 toggle_dark_mode 回调;此回调在“true”和“false”之间切换 dark-mode 操作的状态

static void
toggle_dark_mode (GSimpleAction *action,
                  GVariant      *parameter G_GNUC_UNUSED,
                  gpointer       user_data G_GNUC_UNUSED)
{
  GVariant *state = g_action_get_state (G_ACTION (action));
  gboolean old_state = g_variant_get_boolean (state);
  gboolean new_state = !old_state;

  g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state));

  g_variant_unref (state);
}
  1. 添加 change_color_scheme 回调;此回调负责使用 AdwStyleManager API 切换应用程序的配色方案

static void
change_color_scheme (GSimpleAction         *action,
                     GVariant              *new_state,
                     TextViewerApplication *self)
{
  gboolean dark_mode = g_variant_get_boolean (new_state);

  AdwStyleManager *style_manager = adw_style_manager_get_default ();

  if (dark_mode)
    adw_style_manager_set_color_scheme (style_manager, ADW_COLOR_SCHEME_FORCE_DARK);
  else
    adw_style_manager_set_color_scheme (style_manager, ADW_COLOR_SCHEME_DEFAULT);

  g_simple_action_set_state (action, new_state);
}

将深色模式状态存储为设置

如果你想在会话之间保留所选的配色方案,可以将它存储在 GSettings 中,你已经在 保存应用程序状态 中添加了 GSettings。

在设置模式中添加一个新键

  1. 打开 com.example.TextViewer.gschema.xml 文件

  2. 添加一个 dark-mode 布尔键

<?xml version="1.0" encoding="UTF-8"?>
<schemalist gettext-domain="text-viewer">
  <schema id="com.example.TextViewer" path="/com/example/TextViewer/">
    <key name="window-width" type="i">
      <default>600</default>
    </key>
    <key name="window-height" type="i">
      <default>400</default>
    </key>
    <key name="window-maximized" type="b">
      <default>false</default>
    </key>
    <key name="dark-mode" type="b">
      <default>false</default>
    </key>
  </schema>
</schemalist>

将 GSettings 添加到应用程序

  1. GSettings 实例添加到 TextViewerApplication

struct _TextViewerApplication
{
  GtkApplication parent_instance;

  GSettings *settings;
};
  1. TextViewerApplication 实例被释放时清除 GSettings 实例

static void
text_viewer_application_dispose (GObject *gobject)
{
  TextViewerApplication *self = TEXT_VIEWER_APPLICATION (gobject);

  g_clear_object (&self->settings);

  G_OBJECT_CLASS (text_viewer_application_parent_class)->dispose (gobject);
}

static void
text_viewer_application_class_init (TextViewerApplicationClass *klass)
{
  GApplicationClass *app_class = G_APPLICATION_CLASS (klass);
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

  gobject_class->dispose = text_viewer_application_dispose;
  1. TextViewerApplication 的其余部分一起初始化 GSettings 实例

static void
text_viewer_application_init (TextViewerApplication *self)
{
  self->settings = g_settings_new ("com.example.TextViewer");

  g_autoptr (GSimpleAction) quit_action = g_simple_action_new ("quit", NULL);
  g_signal_connect_swapped (quit_action, "activate", G_CALLBACK (g_application_quit), self);
  g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (quit_action));

设置配色方案的初始状态

  1. 检索 dark-mode GSettings 键的值

  2. 使用键的值设置配色方案

  3. 使用键的值初始化 dark-mode 操作的状态

static void
text_viewer_application_init (TextViewerApplication *self)
{
  self->settings = g_settings_new ("com.example.TextViewer");

  gboolean dark_mode = g_settings_get_boolean (self->settings, "dark-mode");
  AdwStyleManager *style_manager = adw_style_manager_get_default ();
  if (dark_mode)
    adw_style_manager_set_color_scheme (style_manager, ADW_COLOR_SCHEME_FORCE_DARK);
  else
    adw_style_manager_set_color_scheme (style_manager, ADW_COLOR_SCHEME_DEFAULT);

  g_autoptr (GSimpleAction) dark_action =
    g_simple_action_new_stateful ("dark-mode", NULL, g_variant_new_boolean (dark_mode));
  g_signal_connect (dark_action, "activate", G_CALLBACK (text_viewer_application_toggle_action), self);
  g_signal_connect (dark_action, "change-state", G_CALLBACK (text_viewer_application_dark_mode_changed), self);
  g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (dark_action));

在配色方案更改时保存它

  1. 每当 dark-mode 操作的状态发生更改时,使用 dark-mode 操作的状态更新 dark-mode GSettings 键。

static void
change_color_scheme (GSimpleAction         *action,
                     GVariant              *value,
                     TextViewerApplication *self)
{
  gboolean dark_mode = g_variant_get_boolean (value);

  AdwStyleManager *style_manager = adw_style_manager_get_default ();

  if (dark_mode)
    adw_style_manager_set_color_scheme (style_manager, ADW_COLOR_SCHEME_FORCE_DARK);
  else
    adw_style_manager_set_color_scheme (style_manager, ADW_COLOR_SCHEME_DEFAULT);

  g_simple_action_set_state (action, value);

  g_settings_set_boolean (self->settings, "dark-mode", dark_mode);
}

在本课程中,你学习了如何为你的应用程序强制深色主题,以及将其存储为应用程序首选项。