[libhandy] Add HdyStyleManager
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libhandy] Add HdyStyleManager
- Date: Fri, 24 Sep 2021 10:52:03 +0000 (UTC)
commit 5bc5788a041e9bfdce90ad7a47efc15f868edb54
Author: Alexander Mikhaylenko <exalm7659 gmail com>
Date: Thu Aug 26 15:49:00 2021 +0500
Add HdyStyleManager
debian/libhandy-1-0.symbols | 9 +
doc/handy-docs.xml | 6 +
src/handy.h | 1 +
src/hdy-enums.c.in | 1 +
src/hdy-style-manager.c | 700 ++++++++++++++++++++++++++++++++++++++++++++
src/hdy-style-manager.h | 57 ++++
src/meson.build | 3 +
tests/meson.build | 1 +
tests/test-style-manager.c | 55 ++++
tools/libhandy-1.4.0.tar.xz | Bin 0 -> 496476 bytes
10 files changed, 833 insertions(+)
---
diff --git a/debian/libhandy-1-0.symbols b/debian/libhandy-1-0.symbols
index 2cc3ee00..17f76f02 100644
--- a/debian/libhandy-1-0.symbols
+++ b/debian/libhandy-1-0.symbols
@@ -317,6 +317,15 @@ libhandy-1.so.0 libhandy-1-0 #MINVER#
hdy_squeezer_set_xalign@LIBHANDY_1_0 0.85.0
hdy_squeezer_set_yalign@LIBHANDY_1_0 0.85.0
hdy_squeezer_transition_type_get_type@LIBHANDY_1_0 0.0.10
+ hdy_style_manager_get_color_scheme@LIBHANDY_1_0 1.6.0
+ hdy_style_manager_get_dark@LIBHANDY_1_0 1.6.0
+ hdy_style_manager_get_default@LIBHANDY_1_0 1.6.0
+ hdy_style_manager_get_display@LIBHANDY_1_0 1.6.0
+ hdy_style_manager_get_for_display@LIBHANDY_1_0 1.6.0
+ hdy_style_manager_get_high_contrast@LIBHANDY_1_0 1.6.0
+ hdy_style_manager_get_system_supports_color_schemes@LIBHANDY_1_0 1.6.0
+ hdy_style_manager_get_type@LIBHANDY_1_0 1.6.0
+ hdy_style_manager_set_color_scheme@LIBHANDY_1_0 1.6.0
hdy_swipe_group_add_swipeable@LIBHANDY_1_0 0.0.12
hdy_swipe_group_get_swipeables@LIBHANDY_1_0 0.0.12
hdy_swipe_group_get_type@LIBHANDY_1_0 0.0.12
diff --git a/doc/handy-docs.xml b/doc/handy-docs.xml
index 2486b0d8..8a96b451 100644
--- a/doc/handy-docs.xml
+++ b/doc/handy-docs.xml
@@ -58,6 +58,7 @@
<xi:include href="xml/hdy-preferences-row.xml"/>
<xi:include href="xml/hdy-preferences-window.xml"/>
<xi:include href="xml/hdy-search-bar.xml"/>
+ <xi:include href="xml/hdy-style-manager.xml"/>
<xi:include href="xml/hdy-squeezer.xml"/>
<xi:include href="xml/hdy-status-page.xml"/>
<xi:include href="xml/hdy-swipeable.xml"/>
@@ -150,6 +151,11 @@
<xi:include href="xml/api-index-1.4.xml"><xi:fallback /></xi:include>
</index>
+ <index id="api-index-1-6" role="1.6">
+ <title>Index of new symbols in 1.6</title>
+ <xi:include href="xml/api-index-1.6.xml"><xi:fallback /></xi:include>
+ </index>
+
<index id="annotations-glossary">
<title>Annotations glossary</title>
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
diff --git a/src/handy.h b/src/handy.h
index dfbc74dc..45f5461e 100644
--- a/src/handy.h
+++ b/src/handy.h
@@ -47,6 +47,7 @@ G_BEGIN_DECLS
#include "hdy-search-bar.h"
#include "hdy-squeezer.h"
#include "hdy-status-page.h"
+#include "hdy-style-manager.h"
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
#include "hdy-swipe-group.h"
G_GNUC_END_IGNORE_DEPRECATIONS
diff --git a/src/hdy-enums.c.in b/src/hdy-enums.c.in
index b9ff3d24..8ea24278 100644
--- a/src/hdy-enums.c.in
+++ b/src/hdy-enums.c.in
@@ -9,6 +9,7 @@
#include "hdy-leaflet.h"
#include "hdy-navigation-direction.h"
#include "hdy-squeezer.h"
+#include "hdy-style-manager.h"
#include "hdy-view-switcher.h"
/*** END file-header ***/
diff --git a/src/hdy-style-manager.c b/src/hdy-style-manager.c
new file mode 100644
index 00000000..00c069d6
--- /dev/null
+++ b/src/hdy-style-manager.c
@@ -0,0 +1,700 @@
+/*
+ * Copyright (C) 2021 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * Author: Alexander Mikhaylenko <alexander mikhaylenko puri sm>
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#include "hdy-style-manager.h"
+
+#include "hdy-settings-private.h"
+#include <gtk/gtk.h>
+
+#define SWITCH_DURATION 250
+
+/**
+ * HdyColorScheme:
+ * @HDY_COLOR_SCHEME_DEFAULT: Inherit the parent color-scheme. When set on the
+ * #HdyStyleManager returned by hdy_style_manager_get_default(), it's
+ * equivalent to %HDY_COLOR_SCHEME_FORCE_LIGHT.
+ * @HDY_COLOR_SCHEME_FORCE_LIGHT: Always use light appearance.
+ * @HDY_COLOR_SCHEME_PREFER_LIGHT: Use light appearance unless the system
+ * prefers dark colors.
+ * @HDY_COLOR_SCHEME_PREFER_DARK: Use dark appearance unless the system prefers
+ * light colors.
+ * @HDY_COLOR_SCHEME_FORCE_DARK: Always use dark appearance.
+ *
+ * Application color schemes for #HdyStyleManager:color-scheme.
+ *
+ * Since: 1.6
+ */
+
+/**
+ * SECTION:hdy-style-manager
+ * @short_description: A class for managing application-wide styling
+ * @title: HdyStyleManager
+ *
+ * #HdyStyleManager provides a way to query and influence the application styles
+ * such as whether to use dark or high contrast appearance.
+ *
+ * It allows to set the color scheme via the #HdyStyleManager:color-scheme
+ * property, and to query the current appearance, as well as whether a
+ * system-wide color scheme preference exists.
+ *
+ * Important: #GtkSettings:gtk-application-prefer-dark-theme should
+ * not be used together with `HdyStyleManager` and will result in a warning.
+ * Color schemes should be used instead.
+ *
+ * Since: 1.6
+ */
+
+struct _HdyStyleManager
+{
+ GObject parent_instance;
+
+ GdkDisplay *display;
+ HdySettings *settings;
+
+ HdyColorScheme color_scheme;
+ gboolean dark;
+
+ guint animation_timeout_id;
+};
+
+G_DEFINE_TYPE (HdyStyleManager, hdy_style_manager, G_TYPE_OBJECT);
+
+enum {
+ PROP_0,
+ PROP_DISPLAY,
+ PROP_COLOR_SCHEME,
+ PROP_SYSTEM_SUPPORTS_COLOR_SCHEMES,
+ PROP_DARK,
+ PROP_HIGH_CONTRAST,
+ LAST_PROP,
+};
+
+static GParamSpec *props[LAST_PROP];
+
+static GHashTable *display_style_managers = NULL;
+static HdyStyleManager *default_instance = NULL;
+
+static void
+warn_prefer_dark_theme (HdyStyleManager *self)
+{
+ g_warning ("Using GtkSettings:gtk-application-prefer-dark-theme together "
+ "with HdyStyleManager is unsupported. Please use "
+ "HdyStyleManager:color-scheme instead.");
+}
+
+static void
+unregister_display (GdkDisplay *display)
+{
+ g_assert (!g_hash_table_contains (display_style_managers, display));
+
+ g_hash_table_remove (display_style_managers, display);
+}
+
+static void
+register_display (GdkDisplayManager *display_manager,
+ GdkDisplay *display)
+{
+ HdyStyleManager *style_manager;
+
+ style_manager = g_object_new (HDY_TYPE_STYLE_MANAGER,
+ "display", display,
+ NULL);
+
+ g_assert (!g_hash_table_contains (display_style_managers, display));
+
+ g_hash_table_insert (display_style_managers, display, style_manager);
+
+ g_signal_connect (display,
+ "closed",
+ G_CALLBACK (unregister_display),
+ NULL);
+}
+
+static char *
+get_system_theme_name (void)
+{
+ GdkScreen *screen = gdk_screen_get_default ();
+ g_auto (GValue) value = G_VALUE_INIT;
+
+ g_value_init (&value, G_TYPE_STRING);
+ if (!gdk_screen_get_setting (screen, "gtk-theme-name", &value))
+ return g_strdup ("Adwaita");
+
+ return g_value_dup_string (&value);
+}
+
+static gboolean
+enable_animations_cb (HdyStyleManager *self)
+{
+ GdkScreen *screen = gdk_display_get_default_screen (self->display);
+
+ g_object_set (gtk_settings_get_for_screen (screen),
+ "gtk-enable-animations", TRUE,
+ NULL);
+
+ self->animation_timeout_id = 0;
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+update_stylesheet (HdyStyleManager *self)
+{
+ GdkScreen *screen;
+ GtkSettings *gtk_settings;
+ const char *theme_name;
+ gboolean enable_animations;
+
+ if (!self->display)
+ return;
+
+ screen = gdk_display_get_default_screen (self->display);
+ gtk_settings = gtk_settings_get_for_screen (screen);
+
+ if (hdy_settings_get_high_contrast (self->settings))
+ theme_name = g_strdup (self->dark ? "HighContrastInverse" : "HighContrast");
+ else
+ theme_name = get_system_theme_name ();
+
+ if (self->animation_timeout_id) {
+ g_clear_handle_id (&self->animation_timeout_id, g_source_remove);
+ enable_animations = TRUE;
+ } else {
+ g_object_get (gtk_settings,
+ "gtk-enable-animations", &enable_animations,
+ NULL);
+ }
+
+ g_signal_handlers_block_by_func (gtk_settings,
+ G_CALLBACK (warn_prefer_dark_theme),
+ self);
+
+ g_object_set (gtk_settings,
+ "gtk-enable-animations", FALSE,
+ "gtk-theme-name", theme_name,
+ "gtk-application-prefer-dark-theme", self->dark,
+ NULL);
+
+ g_signal_handlers_unblock_by_func (gtk_settings,
+ G_CALLBACK (warn_prefer_dark_theme),
+ self);
+
+ if (enable_animations) {
+ self->animation_timeout_id =
+ g_timeout_add (SWITCH_DURATION,
+ G_SOURCE_FUNC (enable_animations_cb),
+ self);
+ }
+}
+
+static inline gboolean
+get_is_dark (HdyStyleManager *self)
+{
+ HdySystemColorScheme system_scheme = hdy_settings_get_color_scheme (self->settings);
+
+ switch (self->color_scheme) {
+ case HDY_COLOR_SCHEME_DEFAULT:
+ if (self->display)
+ return get_is_dark (default_instance);
+ return FALSE;
+ case HDY_COLOR_SCHEME_FORCE_LIGHT:
+ return FALSE;
+ case HDY_COLOR_SCHEME_PREFER_LIGHT:
+ return system_scheme == HDY_SYSTEM_COLOR_SCHEME_PREFER_DARK;
+ case HDY_COLOR_SCHEME_PREFER_DARK:
+ return system_scheme != HDY_SYSTEM_COLOR_SCHEME_PREFER_LIGHT;
+ case HDY_COLOR_SCHEME_FORCE_DARK:
+ return TRUE;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+update_dark (HdyStyleManager *self)
+{
+ gboolean dark = get_is_dark (self);
+
+ if (dark == self->dark)
+ return;
+
+ self->dark = dark;
+
+ update_stylesheet (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DARK]);
+}
+
+static void
+notify_high_contrast_cb (HdyStyleManager *self)
+{
+ update_stylesheet (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_HIGH_CONTRAST]);
+}
+
+static void
+hdy_style_manager_constructed (GObject *object)
+{
+ HdyStyleManager *self = HDY_STYLE_MANAGER (object);
+
+ G_OBJECT_CLASS (hdy_style_manager_parent_class)->constructed (object);
+
+ if (self->display) {
+ GdkScreen *screen = gdk_display_get_default_screen (self->display);
+ GtkSettings *settings = gtk_settings_get_for_screen (screen);
+ gboolean prefer_dark_theme;
+
+ g_object_get (settings,
+ "gtk-application-prefer-dark-theme", &prefer_dark_theme,
+ NULL);
+
+ if (prefer_dark_theme)
+ warn_prefer_dark_theme (self);
+
+ g_signal_connect_object (settings,
+ "notify::gtk-application-prefer-dark-theme",
+ G_CALLBACK (warn_prefer_dark_theme),
+ self,
+ G_CONNECT_SWAPPED);
+ }
+
+ self->settings = hdy_settings_get_default ();
+
+ g_signal_connect_object (self->settings,
+ "notify::color-scheme",
+ G_CALLBACK (update_dark),
+ self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (self->settings,
+ "notify::high-contrast",
+ G_CALLBACK (notify_high_contrast_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ update_dark (self);
+ update_stylesheet (self);
+}
+
+static void
+hdy_style_manager_dispose (GObject *object)
+{
+ HdyStyleManager *self = HDY_STYLE_MANAGER (object);
+
+ g_clear_handle_id (&self->animation_timeout_id, g_source_remove);
+
+ G_OBJECT_CLASS (hdy_style_manager_parent_class)->dispose (object);
+}
+
+static void
+hdy_style_manager_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ HdyStyleManager *self = HDY_STYLE_MANAGER (object);
+
+ switch (prop_id) {
+ case PROP_DISPLAY:
+ g_value_set_object (value, hdy_style_manager_get_display (self));
+ break;
+
+ case PROP_COLOR_SCHEME:
+ g_value_set_enum (value, hdy_style_manager_get_color_scheme (self));
+ break;
+
+ case PROP_SYSTEM_SUPPORTS_COLOR_SCHEMES:
+ g_value_set_boolean (value, hdy_style_manager_get_system_supports_color_schemes (self));
+ break;
+
+ case PROP_DARK:
+ g_value_set_boolean (value, hdy_style_manager_get_dark (self));
+ break;
+
+ case PROP_HIGH_CONTRAST:
+ g_value_set_boolean (value, hdy_style_manager_get_high_contrast (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+hdy_style_manager_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ HdyStyleManager *self = HDY_STYLE_MANAGER (object);
+
+ switch (prop_id) {
+ case PROP_DISPLAY:
+ self->display = g_value_get_object (value);
+ break;
+
+ case PROP_COLOR_SCHEME:
+ hdy_style_manager_set_color_scheme (self, g_value_get_enum (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+hdy_style_manager_class_init (HdyStyleManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructed = hdy_style_manager_constructed;
+ object_class->dispose = hdy_style_manager_dispose;
+ object_class->get_property = hdy_style_manager_get_property;
+ object_class->set_property = hdy_style_manager_set_property;
+
+ /**
+ * HdyStyleManager:display:
+ *
+ * The display the style manager is associated with.
+ *
+ * The display will be %NULL for the style manager returned by
+ * hdy_style_manager_get_default().
+ *
+ * Since: 1.6
+ */
+ props[PROP_DISPLAY] =
+ g_param_spec_object ("display",
+ "Display",
+ "Display",
+ GDK_TYPE_DISPLAY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+ /**
+ * HdyStyleManager:color-scheme:
+ *
+ * The requested application color scheme.
+ *
+ * The effective appearance will be decided based on the application color
+ * scheme and the system preferred color scheme. The #HdyStyleManager:dark
+ * property can be used to query the current effective appearance.
+ *
+ * The %HDY_COLOR_SCHEME_PREFER_LIGHT color scheme results in the application
+ * using light appearance unless the system prefers dark colors. This is the
+ * default value.
+ *
+ * The %HDY_COLOR_SCHEME_PREFER_DARK color scheme results in the application
+ * using dark appearance, but can still switch to the light appearance if the
+ * system can prefers it, for example, when the high contrast preference is
+ * enabled.
+ *
+ * The %HDY_COLOR_SCHEME_FORCE_LIGHT and %HDY_COLOR_SCHEME_FORCE_DARK values
+ * ignore the system preference entirely, they are useful if the application
+ * wants to match its UI to its content or to provide a separate color scheme
+ * switcher.
+ *
+ * If a per-#GdkDisplay style manager has its color scheme set to
+ * %HDY_COLOR_SCHEME_DEFAULT, it will inherit the color scheme from the
+ * default style manager.
+ *
+ * For the default style manager, %HDY_COLOR_SCHEME_DEFAULT is equivalent to
+ * %HDY_COLOR_SCHEME_FORCE_LIGHT.
+ *
+ * The #HdyStyleManager:system-supports-color-schemes property can be used to
+ * check if the current environment provides a color scheme dddpreference.
+ *
+ * Since: 1.6
+ */
+ props[PROP_COLOR_SCHEME] =
+ g_param_spec_enum ("color-scheme",
+ _("Color Scheme"),
+ _("The current color scheme"),
+ HDY_TYPE_COLOR_SCHEME,
+ HDY_COLOR_SCHEME_DEFAULT,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+ /**
+ * HdyStyleManager:system-supports-color-schemes:
+ *
+ * Whether the system supports color schemes.
+ *
+ * This property can be used to check if the current environment provides a
+ * color scheme preference. For example, applications might want to show a
+ * separate appearance switcher if it's set to %FALSE.
+ *
+ * It's only set at startup and cannot change its value later.
+ *
+ * See #HdyStyleManager:color-scheme.
+ *
+ * Since: 1.6
+ */
+ props[PROP_SYSTEM_SUPPORTS_COLOR_SCHEMES] =
+ g_param_spec_boolean ("system-supports-color-schemes",
+ _("System supports color schemes"),
+ _("Whether the system supports color schemes"),
+ FALSE,
+ G_PARAM_READABLE);
+
+ /**
+ * HdyStyleManager:dark:
+ *
+ * Whether the application is using dark appearance.
+ *
+ * This property can be used to query the current appearance, as requested via
+ * #HdyStyleManager:color-scheme.
+ *
+ * Since: 1.6
+ */
+ props[PROP_DARK] =
+ g_param_spec_boolean ("dark",
+ _("Dark"),
+ _("Whether the application is using dark appearance"),
+ FALSE,
+ G_PARAM_READABLE);
+
+ /**
+ * HdyStyleManager:high-contrast:
+ *
+ * Whether the application is using high contrast appearance.
+ *
+ * This cannot be overridden by applications.
+ *
+ * Since: 1.6
+ */
+ props[PROP_HIGH_CONTRAST] =
+ g_param_spec_boolean ("high-contrast",
+ _("High Contrast"),
+ _("Whether the application is using high contrast appearance"),
+ FALSE,
+ G_PARAM_READABLE);
+
+ g_object_class_install_properties (object_class, LAST_PROP, props);
+}
+
+static void
+hdy_style_manager_init (HdyStyleManager *self)
+{
+ self->color_scheme = HDY_COLOR_SCHEME_DEFAULT;
+}
+
+static void
+hdy_style_manager_ensure (void)
+{
+ GdkDisplayManager *display_manager = gdk_display_manager_get ();
+ g_autoptr (GSList) displays = NULL;
+ GSList *l;
+
+ if (display_style_managers)
+ return;
+
+ default_instance = g_object_new (HDY_TYPE_STYLE_MANAGER, NULL);
+ display_style_managers = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+
+ displays = gdk_display_manager_list_displays (display_manager);
+
+ for (l = displays; l; l = l->next)
+ register_display (display_manager, l->data);
+
+ g_signal_connect (display_manager,
+ "display-opened",
+ G_CALLBACK (register_display),
+ NULL);
+}
+
+/**
+ * hdy_style_manager_get_default:
+ *
+ * Gets the default #HdyStyleManager instance.
+ *
+ * It manages all #GdkDisplay instances unless the style manager for that
+ * display has an override.
+ *
+ * See hdy_style_manager_get_for_display().
+ *
+ * Returns: (transfer none): the default style manager
+ *
+ * Since: 1.6
+ */
+HdyStyleManager *
+hdy_style_manager_get_default (void)
+{
+ if (!default_instance)
+ hdy_style_manager_ensure ();
+
+ return default_instance;
+}
+
+/**
+ * hdy_style_manager_get_for_display:
+ * @display: a #GdkDisplay
+ *
+ * Gets the #HdyStyleManager instance managing @display.
+ *
+ * It can be used to override styles for that specific display instead of the
+ * whole application.
+ *
+ * Most applications should use hdy_style_manager_get_default() instead.
+ *
+ * Returns: (transfer none): the style manager for @display
+ *
+ * Since: 1.6
+ */
+HdyStyleManager *
+hdy_style_manager_get_for_display (GdkDisplay *display)
+{
+ g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+ if (!display_style_managers)
+ hdy_style_manager_ensure ();
+
+ g_return_val_if_fail (g_hash_table_contains (display_style_managers, display), NULL);
+
+ return g_hash_table_lookup (display_style_managers, display);
+}
+
+/**
+ * hdy_style_manager_get_display:
+ * @self: a #HdyStyleManager
+ *
+ * Gets the display the style manager is associated with.
+ *
+ * The display will be %NULL for the style manager returned by
+ * hdy_style_manager_get_default().
+ *
+ * Returns: (transfer none): (nullable): the display
+ *
+ * Since: 1.6
+ */
+GdkDisplay *
+hdy_style_manager_get_display (HdyStyleManager *self)
+{
+ g_return_val_if_fail (HDY_IS_STYLE_MANAGER (self), NULL);
+
+ return self->display;
+}
+
+/**
+ * hdy_style_manager_get_color_scheme:
+ * @self: a #HdyStyleManager
+ *
+ * Gets the requested application color scheme.
+ *
+ * Returns: the color scheme
+ *
+ * Since: 1.6
+ */
+HdyColorScheme
+hdy_style_manager_get_color_scheme (HdyStyleManager *self)
+{
+ g_return_val_if_fail (HDY_IS_STYLE_MANAGER (self), HDY_COLOR_SCHEME_DEFAULT);
+
+ return self->color_scheme;
+}
+
+/**
+ * hdy_style_manager_set_color_scheme:
+ * @self: a #HdyStyleManager
+ * @color_scheme: the color scheme
+ *
+ * Sets the requested application color scheme.
+ *
+ * The effective appearance will be decided based on the application color
+ * scheme and the system preferred color scheme. The #HdyStyleManager:dark
+ * property can be used to query the current effective appearance.
+ *
+ * Since: 1.6
+ */
+void
+hdy_style_manager_set_color_scheme (HdyStyleManager *self,
+ HdyColorScheme color_scheme)
+{
+ g_return_if_fail (HDY_IS_STYLE_MANAGER (self));
+
+ if (color_scheme == self->color_scheme)
+ return;
+
+ self->color_scheme = color_scheme;
+
+ g_object_freeze_notify (G_OBJECT (self));
+
+ update_dark (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_COLOR_SCHEME]);
+
+ g_object_thaw_notify (G_OBJECT (self));
+
+ if (!self->display) {
+ GHashTableIter iter;
+ HdyStyleManager *manager;
+
+ g_hash_table_iter_init (&iter, display_style_managers);
+
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer) &manager))
+ if (manager->color_scheme == HDY_COLOR_SCHEME_DEFAULT)
+ update_dark (manager);
+ }
+}
+
+/**
+ * hdy_style_manager_get_system_supports_color_schemes:
+ * @self: a #HdyStyleManager
+ *
+ * Gets whether the system supports color schemes.
+ *
+ * Returns: whether the system supports color schemes
+ *
+ * Since: 1.6
+ */
+gboolean
+hdy_style_manager_get_system_supports_color_schemes (HdyStyleManager *self)
+{
+ g_return_val_if_fail (HDY_IS_STYLE_MANAGER (self), FALSE);
+
+ return hdy_settings_has_color_scheme (self->settings);
+}
+
+/**
+ * hdy_style_manager_get_dark:
+ * @self: a #HdyStyleManager
+ *
+ * Gets whether the application is using dark appearance.
+ *
+ * Returns: whether the application is using dark appearance
+ *
+ * Since: 1.6
+ */
+gboolean
+hdy_style_manager_get_high_contrast (HdyStyleManager *self)
+{
+ g_return_val_if_fail (HDY_IS_STYLE_MANAGER (self), FALSE);
+
+ return hdy_settings_get_high_contrast (self->settings);
+}
+
+/**
+ * hdy_style_manager_get_high_contrast:
+ * @self: a #HdyStyleManager
+ *
+ * Gets whether the application is using high contrast appearance.
+ *
+ * Returns: whether the application is using high contrast appearance
+ *
+ * Since: 1.6
+ */
+gboolean
+hdy_style_manager_get_dark (HdyStyleManager *self)
+{
+ g_return_val_if_fail (HDY_IS_STYLE_MANAGER (self), FALSE);
+
+ return self->dark;
+}
diff --git a/src/hdy-style-manager.h b/src/hdy-style-manager.h
new file mode 100644
index 00000000..a0a175ab
--- /dev/null
+++ b/src/hdy-style-manager.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ *
+ * Author: Alexander Mikhaylenko <alexander mikhaylenko puri sm>
+ */
+
+#pragma once
+
+#if !defined(_HANDY_INSIDE) && !defined(HANDY_COMPILATION)
+#error "Only <handy.h> can be included directly."
+#endif
+
+#include "hdy-version.h"
+
+#include <gtk/gtk.h>
+#include "hdy-enums.h"
+
+G_BEGIN_DECLS
+
+#define HDY_TYPE_STYLE_MANAGER (hdy_style_manager_get_type())
+
+typedef enum {
+ HDY_COLOR_SCHEME_DEFAULT,
+ HDY_COLOR_SCHEME_FORCE_LIGHT,
+ HDY_COLOR_SCHEME_PREFER_LIGHT,
+ HDY_COLOR_SCHEME_PREFER_DARK,
+ HDY_COLOR_SCHEME_FORCE_DARK,
+} HdyColorScheme;
+
+HDY_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (HdyStyleManager, hdy_style_manager, HDY, STYLE_MANAGER, GObject)
+
+HDY_AVAILABLE_IN_ALL
+HdyStyleManager *hdy_style_manager_get_default (void);
+HDY_AVAILABLE_IN_ALL
+HdyStyleManager *hdy_style_manager_get_for_display (GdkDisplay *display);
+
+HDY_AVAILABLE_IN_ALL
+GdkDisplay *hdy_style_manager_get_display (HdyStyleManager *self);
+
+HDY_AVAILABLE_IN_ALL
+HdyColorScheme hdy_style_manager_get_color_scheme (HdyStyleManager *self);
+HDY_AVAILABLE_IN_ALL
+void hdy_style_manager_set_color_scheme (HdyStyleManager *self,
+ HdyColorScheme color_scheme);
+
+HDY_AVAILABLE_IN_ALL
+gboolean hdy_style_manager_get_system_supports_color_schemes (HdyStyleManager *self);
+
+HDY_AVAILABLE_IN_ALL
+gboolean hdy_style_manager_get_dark (HdyStyleManager *self);
+HDY_AVAILABLE_IN_ALL
+gboolean hdy_style_manager_get_high_contrast (HdyStyleManager *self);
+
+G_END_DECLS
diff --git a/src/meson.build b/src/meson.build
index cfea194c..a4be923b 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -15,6 +15,7 @@ hdy_public_enum_headers = [
'hdy-leaflet.h',
'hdy-navigation-direction.h',
'hdy-squeezer.h',
+ 'hdy-style-manager.h',
'hdy-tab-bar.h',
'hdy-view-switcher.h',
]
@@ -93,6 +94,7 @@ src_headers = [
'hdy-search-bar.h',
'hdy-squeezer.h',
'hdy-status-page.h',
+ 'hdy-style-manager.h',
'hdy-swipe-group.h',
'hdy-swipe-tracker.h',
'hdy-swipeable.h',
@@ -157,6 +159,7 @@ src_sources = [
'hdy-squeezer.c',
'hdy-stackable-box.c',
'hdy-status-page.c',
+ 'hdy-style-manager.c',
'hdy-swipe-group.c',
'hdy-swipe-tracker.c',
'hdy-swipeable.c',
diff --git a/tests/meson.build b/tests/meson.build
index 95210ba0..143bd6e0 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -40,6 +40,7 @@ test_names = [
'test-search-bar',
'test-squeezer',
'test-status-page',
+ 'test-style-manager',
'test-swipe-group',
'test-tab-bar',
'test-tab-view',
diff --git a/tests/test-style-manager.c b/tests/test-style-manager.c
new file mode 100644
index 00000000..468b8b52
--- /dev/null
+++ b/tests/test-style-manager.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * Author: Alexander Mikhaylenko <alexander mikhaylenko puri sm>
+ */
+
+#include <handy.h>
+
+int notified;
+
+static void
+notify_cb (GtkWidget *widget, gpointer data)
+{
+ notified++;
+}
+
+static void
+test_hdy_style_manager_color_scheme (void)
+{
+ HdyStyleManager *manager = hdy_style_manager_get_default ();
+ HdyColorScheme color_scheme;
+
+ notified = 0;
+ g_signal_connect (manager, "notify::color-scheme", G_CALLBACK (notify_cb), NULL);
+
+ g_object_get (manager, "color-scheme", &color_scheme, NULL);
+ g_assert_cmpint (color_scheme, ==, HDY_COLOR_SCHEME_DEFAULT);
+ g_assert_cmpint (notified, ==, 0);
+
+ hdy_style_manager_set_color_scheme (manager, HDY_COLOR_SCHEME_DEFAULT);
+ g_assert_cmpint (notified, ==, 0);
+
+ hdy_style_manager_set_color_scheme (manager, HDY_COLOR_SCHEME_PREFER_DARK);
+ g_object_get (manager, "color-scheme", &color_scheme, NULL);
+ g_assert_cmpint (color_scheme, ==, HDY_COLOR_SCHEME_PREFER_DARK);
+ g_assert_cmpint (notified, ==, 1);
+
+ g_object_set (manager, "color-scheme", HDY_COLOR_SCHEME_PREFER_LIGHT, NULL);
+ g_assert_cmpint (hdy_style_manager_get_color_scheme (manager), ==, HDY_COLOR_SCHEME_PREFER_LIGHT);
+ g_assert_cmpint (notified, ==, 2);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ gtk_test_init (&argc, &argv, NULL);
+ hdy_init ();
+
+ g_test_add_func("/Hdyaita/StyleManager/color_scheme", test_hdy_style_manager_color_scheme);
+
+ return g_test_run();
+}
diff --git a/tools/libhandy-1.4.0.tar.xz b/tools/libhandy-1.4.0.tar.xz
new file mode 100644
index 00000000..572a7a54
Binary files /dev/null and b/tools/libhandy-1.4.0.tar.xz differ
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]