[libadwaita] Introduce the AdwApplication class



commit 9b6efa65dabb795c1d48fd0a3c0d5c18a0302017
Author: Nahuel Gomez Castro <nahuel gomezcastro outlook com ar>
Date:   Mon Jun 28 22:33:06 2021 -0300

    Introduce the AdwApplication class
    
    A base class that will take care of the initialization of the library and
    provide extra functionalities such as the autoloading of custom stylesheets

 src/adw-application.c | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/adw-application.h |  40 +++++++++
 src/adw-main.c        |   3 +-
 src/adwaita.h         |   1 +
 src/meson.build       |   2 +
 5 files changed, 275 insertions(+), 1 deletion(-)
---
diff --git a/src/adw-application.c b/src/adw-application.c
new file mode 100644
index 00000000..be283290
--- /dev/null
+++ b/src/adw-application.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2021 Nahuel Gomez Castro
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+#include "adw-application.h"
+#include "adw-main-private.h"
+
+/**
+ * AdwApplication:
+ *
+ * A base class for Adwaita applications.
+ *
+ * `AdwApplication` handles library initialization by calling [func Adw init] in
+ * the default `GApplication::startup` signal handler, in turn chaining up as
+ * required by [class@Gtk.Application]. Therefore, any subclass of
+ * `AdwApplication` should always chain up its `GApplication::startup` handler
+ * before using any Adwaita or GTK API.
+ *
+ * ## Automatic Resources
+ *
+ * `AdwApplication` will automatically load stylesheets located in the
+ * application's resource base path (see
+ * `g_application_set_resource_base_path()`), if they're present.
+ *
+ * They can be used to add custom styles to the application, as follows:
+ *
+ * - `style.css` contains styles that are always present.
+ *
+ * - `style-dark.css` contains styles only used when
+ *   [property@Gtk.Settings:gtk-application-prefer-dark-theme] is set to `TRUE`.
+ *
+ * - `style-hc.css` contains styles used when the system high contrast
+ *   preference is enabled.
+ *
+ * - `style-hc-dark.css` contains styles used when the system high contrast
+ *   preference is enabled and
+ *   [property@Gtk.Settings:gtk-application-prefer-dark-theme] is set to `TRUE`.
+ *
+ * Since: 1.0
+ */
+
+typedef struct
+{
+  GtkStyleProvider *base_style_provider;
+  GtkStyleProvider *dark_style_provider;
+  GtkStyleProvider *hc_style_provider;
+  GtkStyleProvider *hc_dark_style_provider;
+} AdwApplicationPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (AdwApplication, adw_application, GTK_TYPE_APPLICATION)
+
+static inline void
+style_provider_set_enabled (GtkStyleProvider *provider,
+                            gboolean          enabled)
+{
+  if (enabled)
+    gtk_style_context_add_provider_for_display (gdk_display_get_default (),
+                                                provider,
+                                                GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+  else
+    gtk_style_context_remove_provider_for_display (gdk_display_get_default (),
+                                                   provider);
+}
+
+static void
+update_stylesheet (AdwApplication *self)
+{
+  AdwApplicationPrivate *priv = adw_application_get_instance_private (self);
+  gboolean is_dark, is_hc, is_hc_dark;
+  const char *theme_name;
+
+  g_object_get (gtk_settings_get_default (),
+                "gtk-theme-name", &theme_name,
+                NULL);
+
+  is_dark = !g_strcmp0 (theme_name, "Adwaita-dark");
+  is_hc = !g_strcmp0 (theme_name, "Adwaita-hc");
+  is_hc_dark = !g_strcmp0 (theme_name, "Adwaita-hc-dark");
+
+  if (priv->dark_style_provider)
+    style_provider_set_enabled (priv->dark_style_provider, is_dark || is_hc_dark);
+
+  if (priv->hc_style_provider)
+    style_provider_set_enabled (priv->hc_style_provider, is_hc || is_hc_dark);
+
+  if (priv->hc_dark_style_provider)
+    style_provider_set_enabled (priv->hc_dark_style_provider, is_hc_dark);
+}
+
+static void
+init_provider_from_file (GtkStyleProvider **provider,
+                         GFile             *file)
+{
+  if (!g_file_query_exists (file, NULL)) {
+    g_clear_object (&file);
+    return;
+  }
+
+  *provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
+  gtk_css_provider_load_from_file (GTK_CSS_PROVIDER (*provider), file);
+
+  g_clear_object (&file);
+}
+
+static void
+init_providers (AdwApplication *self)
+{
+  AdwApplicationPrivate *priv = adw_application_get_instance_private (self);
+
+  const char *base_path = NULL;
+  g_autofree char *base_uri = NULL;
+  g_autoptr (GFile) base_file = NULL;
+
+  base_path = g_application_get_resource_base_path (G_APPLICATION (self));
+
+  if (base_path == NULL)
+    return;
+
+  base_uri = g_strconcat ("resource://", base_path, NULL);
+  base_file = g_file_new_for_uri (base_uri);
+
+  init_provider_from_file (&priv->base_style_provider,
+                           g_file_get_child (base_file, "style.css"));
+  init_provider_from_file (&priv->dark_style_provider,
+                           g_file_get_child (base_file, "style-dark.css"));
+  init_provider_from_file (&priv->hc_style_provider,
+                           g_file_get_child (base_file, "style-hc.css"));
+  init_provider_from_file (&priv->hc_dark_style_provider,
+                           g_file_get_child (base_file, "style-hc-dark.css"));
+}
+
+static void
+init_styling (AdwApplication *self)
+{
+  AdwApplicationPrivate *priv = adw_application_get_instance_private (self);
+
+  GdkDisplay *display = gdk_display_get_default ();
+
+  if (display == NULL)
+    return;
+
+  if (priv->base_style_provider != NULL)
+    gtk_style_context_add_provider_for_display (display,
+                                                priv->base_style_provider,
+                                                GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+  /* If gdk_display_get_default() worked, it means that
+   * gtk_settings get_default() won't return NULL, so we don't
+   * need to check it separately */
+  g_signal_connect_object (gtk_settings_get_default (),
+                           "notify::gtk-theme-name",
+                           G_CALLBACK (update_stylesheet),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  update_stylesheet (self);
+}
+
+static void
+adw_application_startup (GApplication *application)
+{
+  AdwApplication *self = ADW_APPLICATION (application);
+
+  G_APPLICATION_CLASS (adw_application_parent_class)->startup (application);
+
+  adw_init ();
+
+  init_providers (self);
+  init_styling (self);
+}
+
+static void
+adw_application_dispose (GObject *object)
+{
+  AdwApplication *self = ADW_APPLICATION (object);
+  AdwApplicationPrivate *priv = adw_application_get_instance_private (self);
+
+  g_clear_object (&priv->base_style_provider);
+  g_clear_object (&priv->dark_style_provider);
+  g_clear_object (&priv->hc_style_provider);
+  g_clear_object (&priv->hc_dark_style_provider);
+
+  G_OBJECT_CLASS (adw_application_parent_class)->dispose (object);
+}
+
+static void
+adw_application_class_init (AdwApplicationClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GApplicationClass *application_class = G_APPLICATION_CLASS (klass);
+
+  object_class->dispose = adw_application_dispose;
+
+  application_class->startup = adw_application_startup;
+}
+
+static void
+adw_application_init (AdwApplication *self)
+{
+}
+
+/**
+ * adw_application_new:
+ * @application_id: (nullable): The application ID
+ * @flags: The application flags
+ *
+ * Creates a new `AdwApplication`.
+ *
+ * If `application_id` is not `NULL`, then it must be valid. See
+ * `g_application_id_is_valid()`.
+ *
+ * If no application ID is given then some features (most notably application
+ * uniqueness) will be disabled.
+ *
+ * Returns: the newly created `AdwApplication`
+ *
+ * Since: 1.0
+ */
+AdwApplication *
+adw_application_new (const char        *application_id,
+                     GApplicationFlags  flags)
+{
+  return g_object_new (ADW_TYPE_APPLICATION,
+                       "application-id", application_id,
+                       "flags", flags,
+                       NULL);
+}
diff --git a/src/adw-application.h b/src/adw-application.h
new file mode 100644
index 00000000..2c5d73de
--- /dev/null
+++ b/src/adw-application.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 Nahuel Gomez Castro
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+#if !defined(_ADWAITA_INSIDE) && !defined(ADWAITA_COMPILATION)
+#error "Only <adwaita.h> can be included directly."
+#endif
+
+#include "adw-version.h"
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define ADW_TYPE_APPLICATION (adw_application_get_type())
+
+ADW_AVAILABLE_IN_ALL
+G_DECLARE_DERIVABLE_TYPE (AdwApplication, adw_application, ADW, APPLICATION, GtkApplication)
+
+/**
+ * AdwApplicationClass:
+ * @parent_class: The parent class
+ */
+struct _AdwApplicationClass
+{
+  GtkApplicationClass parent_class;
+
+  /*< private >*/
+  gpointer padding[4];
+};
+
+ADW_AVAILABLE_IN_ALL
+AdwApplication *adw_application_new (const char        *application_id,
+                                     GApplicationFlags  flags) G_GNUC_WARN_UNUSED_RESULT;
+
+G_END_DECLS
diff --git a/src/adw-main.c b/src/adw-main.c
index 13194ebb..afad88e0 100644
--- a/src/adw-main.c
+++ b/src/adw-main.c
@@ -114,7 +114,8 @@ adw_icons_init (void)
  *
  * Call this function just after initializing GTK, if you are using
  * [class@Gtk.Application] it means it must be called when the
- * `GApplication::startup` signal is emitted.
+ * `GApplication::startup` signal is emitted. There's no need to call this
+ * function if you're using [class@Adw.Application].
  *
  * If Libadwaita has already been initialized, the function will simply return.
  *
diff --git a/src/adwaita.h b/src/adwaita.h
index 8cb47858..9879d538 100644
--- a/src/adwaita.h
+++ b/src/adwaita.h
@@ -23,6 +23,7 @@ G_BEGIN_DECLS
 #include "adw-version.h"
 #include "adw-action-row.h"
 #include "adw-animation-util.h"
+#include "adw-application.h"
 #include "adw-application-window.h"
 #include "adw-avatar.h"
 #include "adw-bin.h"
diff --git a/src/meson.build b/src/meson.build
index 96ecce41..d0b1c90c 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -69,6 +69,7 @@ libadwaita_generated_headers += [adw_public_enums[1]]
 src_headers = [
   'adw-action-row.h',
   'adw-animation-util.h',
+  'adw-application.h',
   'adw-application-window.h',
   'adw-avatar.h',
   'adw-bin.h',
@@ -123,6 +124,7 @@ src_sources = [
   'adw-action-row.c',
   'adw-animation.c',
   'adw-animation-util.c',
+  'adw-application.c',
   'adw-application-window.c',
   'adw-avatar.c',
   'adw-bidi.c',


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]