[mutter] color-profile: Create colord profiles



commit cc84a45b567e0deadcf87d244cfa9d9110dff721
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Tue Nov 30 11:56:31 2021 +0100

    color-profile: Create colord profiles
    
    This works similiarly to how MetaColorDevice works, by creating them
    asynchronously then signalling the 'ready' signal when done. Also
    similarly to MetaColorDevice, the on-demand sync cleanup on finalize is
    added, to avoid race conditions when hotplugs happens very rapidly,
    e.g. in tests.
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2164>

 src/backends/meta-color-device.c  |  28 +++++-
 src/backends/meta-color-profile.c | 207 ++++++++++++++++++++++++++++++++++++++
 src/backends/meta-color-profile.h |   2 +
 3 files changed, 235 insertions(+), 2 deletions(-)
---
diff --git a/src/backends/meta-color-device.c b/src/backends/meta-color-device.c
index 57f6064141..e86d96ef86 100644
--- a/src/backends/meta-color-device.c
+++ b/src/backends/meta-color-device.c
@@ -45,7 +45,8 @@ static guint signals[N_SIGNALS];
 typedef enum
 {
   PENDING_EDID_PROFILE = 1 << 0,
-  PENDING_CONNECTED = 1 << 1,
+  PENDING_PROFILE_READY = 1 << 1,
+  PENDING_CONNECTED = 1 << 2,
 } PendingState;
 
 struct _MetaColorDevice
@@ -59,6 +60,7 @@ struct _MetaColorDevice
   CdDevice *cd_device;
 
   MetaColorProfile *device_profile;
+  gulong device_profile_ready_handler_id;
 
   GCancellable *cancellable;
 
@@ -180,6 +182,8 @@ meta_color_device_dispose (GObject *object)
 
   g_cancellable_cancel (color_device->cancellable);
   g_clear_object (&color_device->cancellable);
+  g_clear_signal_handler (&color_device->device_profile_ready_handler_id,
+                          color_device->device_profile);
 
   g_clear_object (&color_device->device_profile);
 
@@ -283,6 +287,14 @@ on_cd_device_connected (GObject      *source_object,
   maybe_finish_setup (color_device);
 }
 
+static void
+on_profile_ready (MetaColorProfile *color_profile,
+                  MetaColorDevice  *color_device)
+{
+  color_device->pending_state &= ~PENDING_PROFILE_READY;
+  maybe_finish_setup (color_device);
+}
+
 static void
 ensure_device_profile_cb (GObject      *source_object,
                           GAsyncResult *res,
@@ -314,7 +326,18 @@ ensure_device_profile_cb (GObject      *source_object,
   color_device->pending_state &= ~PENDING_EDID_PROFILE;
   g_set_object (&color_device->device_profile, color_profile);
 
-  maybe_finish_setup (color_device);
+  if (!meta_color_profile_is_ready (color_profile))
+    {
+      color_device->device_profile_ready_handler_id =
+        g_signal_connect (color_profile, "ready",
+                          G_CALLBACK (on_profile_ready),
+                          color_device);
+      color_device->pending_state |= PENDING_PROFILE_READY;
+    }
+  else
+    {
+      maybe_finish_setup (color_device);
+    }
 }
 
 static void
@@ -863,6 +886,7 @@ on_efi_panel_color_info_loaded (GObject      *source_object,
           /* Set metadata needed by colord */
           cd_icc_add_metadata (cd_icc, CD_PROFILE_PROPERTY_FILENAME,
                                file_path);
+
           file_md5_checksum = g_compute_checksum_for_bytes (G_CHECKSUM_MD5,
                                                             bytes);
           cd_icc_add_metadata (cd_icc, CD_PROFILE_METADATA_FILE_CHECKSUM,
diff --git a/src/backends/meta-color-profile.c b/src/backends/meta-color-profile.c
index 48b39fa09e..cfd038d84b 100644
--- a/src/backends/meta-color-profile.c
+++ b/src/backends/meta-color-profile.c
@@ -25,6 +25,17 @@
 #include <colord.h>
 #include <gio/gio.h>
 
+#include "backends/meta-color-manager-private.h"
+
+enum
+{
+  READY,
+
+  N_SIGNALS
+};
+
+static guint signals[N_SIGNALS];
+
 struct _MetaColorProfile
 {
   GObject parent;
@@ -33,18 +44,100 @@ struct _MetaColorProfile
 
   CdIcc *cd_icc;
   GBytes *bytes;
+
+  char *cd_profile_id;
+  CdProfile *cd_profile;
+  GCancellable *cancellable;
+
+  gboolean is_ready;
 };
 
 G_DEFINE_TYPE (MetaColorProfile, meta_color_profile,
                G_TYPE_OBJECT)
 
+typedef struct
+{
+  GMainLoop *loop;
+  CdProfile *cd_profile;
+  GError *error;
+} FindProfileData;
+
+static void
+on_find_profile (GObject      *source_object,
+                 GAsyncResult *res,
+                 gpointer      user_data)
+{
+  CdClient *cd_client = CD_CLIENT (source_object);
+  FindProfileData *data = user_data;
+
+  data->cd_profile = cd_client_find_profile_finish (cd_client, res,
+                                                    &data->error);
+  g_main_loop_quit (data->loop);
+}
+
+static CdProfile *
+find_profile_sync (CdClient    *cd_client,
+                   const char  *cd_profile_id,
+                   GError     **error)
+{
+  g_autoptr (GMainContext) main_context = NULL;
+  g_autoptr (GMainLoop) main_loop = NULL;
+  FindProfileData data = {};
+
+  main_context = g_main_context_new ();
+  main_loop = g_main_loop_new (main_context, FALSE);
+  g_main_context_push_thread_default (main_context);
+
+  data = (FindProfileData) {
+    .loop = main_loop,
+  };
+  cd_client_find_profile (cd_client, cd_profile_id, NULL,
+                          on_find_profile,
+                          &data);
+  g_main_loop_run (main_loop);
+
+  g_main_context_pop_thread_default (main_context);
+
+  if (data.error)
+    g_propagate_error (error, data.error);
+  return data.cd_profile;
+}
+
 static void
 meta_color_profile_finalize (GObject *object)
 {
   MetaColorProfile *color_profile = META_COLOR_PROFILE (object);
+  MetaColorManager *color_manager = color_profile->color_manager;
+  CdClient *cd_client = meta_color_manager_get_cd_client (color_manager);
+  CdProfile *cd_profile;
 
+  g_cancellable_cancel (color_profile->cancellable);
+  g_clear_object (&color_profile->cancellable);
+
+  cd_profile = color_profile->cd_profile;
+  if (!cd_profile)
+    {
+      g_autoptr (GError) error = NULL;
+
+      cd_profile = find_profile_sync (cd_client,
+                                      color_profile->cd_profile_id,
+                                      &error);
+      if (!cd_profile &&
+          !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+        {
+          g_warning ("Failed to find colord profile %s: %s",
+                     color_profile->cd_profile_id,
+                     error->message);
+        }
+    }
+
+  if (cd_profile)
+    cd_client_delete_profile (cd_client, cd_profile, NULL, NULL, NULL);
+
+  g_clear_pointer (&color_profile->cd_profile_id, g_free);
   g_clear_object (&color_profile->cd_icc);
   g_clear_pointer (&color_profile->bytes, g_bytes_unref);
+  g_clear_object (&color_profile->cd_profile);
 
   G_OBJECT_CLASS (meta_color_profile_parent_class)->finalize (object);
 }
@@ -55,6 +148,13 @@ meta_color_profile_class_init (MetaColorProfileClass *klass)
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
   object_class->finalize = meta_color_profile_finalize;
+
+  signals[READY] =
+    g_signal_new ("ready",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST, 0,
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 0);
 }
 
 static void
@@ -62,17 +162,118 @@ meta_color_profile_init (MetaColorProfile *color_profile)
 {
 }
 
+static void
+on_cd_profile_connected (GObject      *source_object,
+                         GAsyncResult *res,
+                         gpointer      user_data)
+{
+  CdProfile *cd_profile = CD_PROFILE (source_object);
+  MetaColorProfile *color_profile = user_data;
+  g_autoptr (GError) error = NULL;
+
+  if (!cd_profile_connect_finish (cd_profile, res, &error))
+    {
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        return;
+
+      g_warning ("Failed to connect to colord profile %s: %s",
+                 color_profile->cd_profile_id,
+                 error->message);
+    }
+  else
+    {
+      g_warn_if_fail (g_strcmp0 (cd_profile_get_id (cd_profile),
+                                 color_profile->cd_profile_id) == 0);
+
+      meta_topic (META_DEBUG_COLOR, "Color profile '%s' connected",
+                  color_profile->cd_profile_id);
+    }
+
+  color_profile->is_ready = TRUE;
+  g_signal_emit (color_profile, signals[READY], 0);
+}
+
+static void
+on_cd_profile_created (GObject      *source_object,
+                       GAsyncResult *res,
+                       gpointer      user_data)
+{
+  CdClient *cd_client = CD_CLIENT (source_object);
+  MetaColorProfile *color_profile = META_COLOR_PROFILE (user_data);
+  g_autoptr (GError) error = NULL;
+  CdProfile *cd_profile;
+
+  cd_profile = cd_client_create_profile_finish (cd_client, res, &error);
+  if (!cd_profile)
+    {
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        return;
+
+      g_warning ("Failed to create colord color profile: %s", error->message);
+
+      color_profile->is_ready = TRUE;
+      g_signal_emit (color_profile, signals[READY], 0);
+      return;
+    }
+
+  meta_topic (META_DEBUG_COLOR, "Created colord color profile '%s'",
+              color_profile->cd_profile_id);
+
+  color_profile->cd_profile = cd_profile;
+
+  cd_profile_connect (cd_profile, color_profile->cancellable,
+                      on_cd_profile_connected, color_profile);
+}
+
+static void
+create_cd_profile (MetaColorProfile *color_profile,
+                   const char       *checksum)
+{
+  MetaColorManager *color_manager = color_profile->color_manager;
+  CdClient *cd_client = meta_color_manager_get_cd_client (color_manager);
+  const char *filename;
+  g_autoptr (GHashTable) profile_props = NULL;
+
+  filename = cd_icc_get_metadata_item (color_profile->cd_icc,
+                                       CD_PROFILE_PROPERTY_FILENAME);
+
+  profile_props = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                         NULL, NULL);
+  g_hash_table_insert (profile_props,
+                       (gpointer) CD_PROFILE_PROPERTY_FILENAME,
+                       (gpointer) filename);
+  g_hash_table_insert (profile_props,
+                       (gpointer) CD_PROFILE_METADATA_FILE_CHECKSUM,
+                       (gpointer) checksum);
+  cd_client_create_profile (cd_client,
+                            color_profile->cd_profile_id,
+                            CD_OBJECT_SCOPE_TEMP,
+                            profile_props,
+                            color_profile->cancellable,
+                            on_cd_profile_created,
+                            color_profile);
+}
+
 MetaColorProfile *
 meta_color_profile_new_from_icc (MetaColorManager *color_manager,
                                  CdIcc            *cd_icc,
                                  GBytes           *raw_bytes)
 {
   MetaColorProfile *color_profile;
+  const char *checksum;
+
+  checksum = cd_icc_get_metadata_item (cd_icc,
+                                       CD_PROFILE_METADATA_FILE_CHECKSUM);
 
   color_profile = g_object_new (META_TYPE_COLOR_PROFILE, NULL);
   color_profile->color_manager = color_manager;
   color_profile->cd_icc = cd_icc;
   color_profile->bytes = raw_bytes;
+  color_profile->cancellable = g_cancellable_new ();
+
+  color_profile->cd_profile_id = g_strdup_printf ("icc-%s", checksum);
+
+  create_cd_profile (color_profile, checksum);
 
   return color_profile;
 }
@@ -101,3 +302,9 @@ meta_color_profile_get_cd_icc (MetaColorProfile *color_profile)
 {
   return color_profile->cd_icc;
 }
+
+gboolean
+meta_color_profile_is_ready (MetaColorProfile *color_profile)
+{
+  return color_profile->is_ready;
+}
diff --git a/src/backends/meta-color-profile.h b/src/backends/meta-color-profile.h
index 7dae530830..6a80c6452b 100644
--- a/src/backends/meta-color-profile.h
+++ b/src/backends/meta-color-profile.h
@@ -44,4 +44,6 @@ size_t meta_color_profile_get_data_size (MetaColorProfile *color_profile);
 META_EXPORT_TEST
 CdIcc * meta_color_profile_get_cd_icc (MetaColorProfile *color_profile);
 
+gboolean meta_color_profile_is_ready (MetaColorProfile *color_profile);
+
 #endif /* META_COLOR_PROFILE_H */


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