feat: notify application after tool initialization
This commit is contained in:
parent
6f2338e72e
commit
349ff157ba
6 changed files with 1779 additions and 16 deletions
|
|
@ -31,6 +31,25 @@ typedef struct
|
|||
gsize version_failed_count;
|
||||
} ToolInitializationSummary;
|
||||
|
||||
/**
|
||||
* @brief Fonction appelée après la fin d’une initialisation.
|
||||
*
|
||||
* Le callback est exécuté sur le contexte principal GLib.
|
||||
*
|
||||
* summary est non NULL uniquement après une réussite.
|
||||
* error est non NULL uniquement lorsqu’une erreur est disponible.
|
||||
*
|
||||
* Les pointeurs summary et error sont empruntés et restent valides
|
||||
* uniquement pendant l’appel du callback.
|
||||
*/
|
||||
typedef void (*ToolInitializerCompletedCallback)(
|
||||
ToolInitializer *tool_initializer,
|
||||
BackgroundTaskState final_state,
|
||||
const ToolInitializationSummary *summary,
|
||||
const GError *error,
|
||||
gpointer user_data
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Codes d’erreur de ToolInitializer.
|
||||
*/
|
||||
|
|
@ -150,6 +169,35 @@ ToolRegistry *tool_initializer_get_registry(
|
|||
ToolInitializer *tool_initializer
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Enregistre le callback appelé après chaque initialisation.
|
||||
*
|
||||
* Le même callback est conservé pour les lancements suivants.
|
||||
*
|
||||
* En passant callback == NULL, l’enregistrement actuel est supprimé.
|
||||
*
|
||||
* Lorsque destroy_notify est non NULL, ToolInitializer devient
|
||||
* responsable de user_data. La fonction de destruction sera appelée
|
||||
* exactement une fois lorsque :
|
||||
*
|
||||
* - le callback est remplacé ;
|
||||
* - le callback est supprimé ;
|
||||
* - l’initialiseur est détruit.
|
||||
*
|
||||
* Le callback est exécuté sur le contexte principal GLib.
|
||||
*
|
||||
* @param tool_initializer Initialiseur concerné.
|
||||
* @param callback Fonction appelée après la fin, ou NULL.
|
||||
* @param user_data Données transmises au callback.
|
||||
* @param destroy_notify Fonction libérant user_data, ou NULL.
|
||||
*/
|
||||
void tool_initializer_set_completed_callback(
|
||||
ToolInitializer *tool_initializer,
|
||||
ToolInitializerCompletedCallback callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy_notify
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Démarre l’initialisation en arrière-plan.
|
||||
*
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -77,6 +77,107 @@ static void application_present_error(
|
|||
const char *message
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Traite la fin de l’initialisation des outils externes.
|
||||
*
|
||||
* Ce callback est exécuté sur le contexte principal GLib.
|
||||
*
|
||||
* @param tool_initializer Initialiseur ayant terminé.
|
||||
* @param final_state État final de la tâche.
|
||||
* @param summary Résumé emprunté en cas de réussite.
|
||||
* @param error Erreur empruntée en cas d’échec.
|
||||
* @param user_data Pointeur emprunté vers Application.
|
||||
*/
|
||||
static void application_on_tool_initialization_completed(
|
||||
ToolInitializer *tool_initializer,
|
||||
BackgroundTaskState final_state,
|
||||
const ToolInitializationSummary *summary,
|
||||
const GError *error,
|
||||
gpointer user_data
|
||||
)
|
||||
{
|
||||
Application *application = user_data;
|
||||
|
||||
if (application == NULL ||
|
||||
tool_initializer == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (tool_initializer !=
|
||||
application->tool_initializer)
|
||||
{
|
||||
g_warning(
|
||||
"Notification reçue depuis un initialiseur inconnu."
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (final_state)
|
||||
{
|
||||
case BACKGROUND_TASK_STATE_COMPLETED:
|
||||
if (summary == NULL)
|
||||
{
|
||||
g_warning(
|
||||
"L’initialisation des outils est terminée "
|
||||
"sans résumé valide."
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
g_message(
|
||||
"Outils externes initialisés : "
|
||||
"%" G_GSIZE_FORMAT " disponibles, "
|
||||
"%" G_GSIZE_FORMAT " absents, "
|
||||
"%" G_GSIZE_FORMAT " versions détectées, "
|
||||
"%" G_GSIZE_FORMAT " versions non détectées.",
|
||||
summary->available_count,
|
||||
summary->missing_count,
|
||||
summary->version_detected_count,
|
||||
summary->version_failed_count
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case BACKGROUND_TASK_STATE_CANCELLED:
|
||||
g_message(
|
||||
"L’initialisation des outils externes a été annulée."
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case BACKGROUND_TASK_STATE_FAILED:
|
||||
g_warning(
|
||||
"L’initialisation des outils externes a échoué : %s",
|
||||
error != NULL
|
||||
? error->message
|
||||
: "erreur inconnue"
|
||||
);
|
||||
|
||||
application_present_error(
|
||||
application,
|
||||
"Initialisation des outils impossible",
|
||||
error != NULL
|
||||
? error->message
|
||||
: "Les outils externes n’ont pas pu être initialisés."
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case BACKGROUND_TASK_STATE_PENDING:
|
||||
case BACKGROUND_TASK_STATE_RUNNING:
|
||||
default:
|
||||
g_warning(
|
||||
"Notification de fin reçue avec un état invalide : %d.",
|
||||
(int) final_state
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Démarre la détection asynchrone des outils externes.
|
||||
*
|
||||
|
|
@ -154,6 +255,20 @@ static void application_present_error(
|
|||
);
|
||||
}
|
||||
|
||||
static void application_on_tool_initialization_completed(
|
||||
ToolInitializer *tool_initializer,
|
||||
BackgroundTaskState final_state,
|
||||
const ToolInitializationSummary *summary,
|
||||
const GError *error,
|
||||
gpointer user_data
|
||||
);
|
||||
|
||||
static void application_present_error(
|
||||
Application *application,
|
||||
const char *title,
|
||||
const char *message
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Installe une nouvelle session et son arbre dans l'application.
|
||||
*
|
||||
|
|
@ -1145,6 +1260,13 @@ Application *application_new(void)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
tool_initializer_set_completed_callback(
|
||||
application->tool_initializer,
|
||||
application_on_tool_initialization_completed,
|
||||
application,
|
||||
NULL
|
||||
);
|
||||
|
||||
application->gtk_application = gtk_application_new(
|
||||
APPLICATION_ID,
|
||||
G_APPLICATION_DEFAULT_FLAGS
|
||||
|
|
@ -1219,6 +1341,16 @@ void application_free(
|
|||
return;
|
||||
}
|
||||
|
||||
if (application->tool_initializer != NULL)
|
||||
{
|
||||
tool_initializer_set_completed_callback(
|
||||
application->tool_initializer,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
task_manager_cancel_all(
|
||||
application->task_manager
|
||||
);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,15 @@
|
|||
#include <gio/gio.h>
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gatomicrefcount reference_count;
|
||||
|
||||
ToolInitializerCompletedCallback callback;
|
||||
gpointer user_data;
|
||||
GDestroyNotify destroy_notify;
|
||||
} ToolInitializerCallbackRegistration;
|
||||
|
||||
/**
|
||||
* @struct ToolInitializer
|
||||
* @brief État interne de l’initialiseur d’outils.
|
||||
|
|
@ -24,11 +33,89 @@ struct ToolInitializer
|
|||
BackgroundTask *task;
|
||||
|
||||
ToolInitializationSummary last_summary;
|
||||
|
||||
ToolInitializerCallbackRegistration *callback_registration;
|
||||
gboolean has_last_summary;
|
||||
gboolean is_running;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Enregistrement immuable d’un callback de fin.
|
||||
*/
|
||||
static ToolInitializerCallbackRegistration *
|
||||
tool_initializer_callback_registration_new(
|
||||
ToolInitializerCompletedCallback callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy_notify
|
||||
)
|
||||
{
|
||||
ToolInitializerCallbackRegistration *registration = NULL;
|
||||
|
||||
if (callback == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
registration = g_new0(
|
||||
ToolInitializerCallbackRegistration,
|
||||
1
|
||||
);
|
||||
|
||||
g_atomic_ref_count_init(
|
||||
®istration->reference_count
|
||||
);
|
||||
|
||||
registration->callback = callback;
|
||||
registration->user_data = user_data;
|
||||
registration->destroy_notify = destroy_notify;
|
||||
|
||||
return registration;
|
||||
}
|
||||
|
||||
static ToolInitializerCallbackRegistration *
|
||||
tool_initializer_callback_registration_ref(
|
||||
ToolInitializerCallbackRegistration *registration
|
||||
)
|
||||
{
|
||||
if (registration == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_atomic_ref_count_inc(
|
||||
®istration->reference_count
|
||||
);
|
||||
|
||||
return registration;
|
||||
}
|
||||
|
||||
static void tool_initializer_callback_registration_unref(
|
||||
ToolInitializerCallbackRegistration *registration
|
||||
)
|
||||
{
|
||||
if (registration == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_atomic_ref_count_dec(
|
||||
®istration->reference_count
|
||||
))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (registration->destroy_notify != NULL)
|
||||
{
|
||||
registration->destroy_notify(
|
||||
registration->user_data
|
||||
);
|
||||
}
|
||||
|
||||
g_free(
|
||||
registration
|
||||
);
|
||||
}
|
||||
|
||||
static gboolean tool_initializer_ensure_catalog_registered(
|
||||
ToolInitializer *tool_initializer,
|
||||
GError **error
|
||||
|
|
@ -69,6 +156,8 @@ static void tool_initializer_unref_internal(
|
|||
BackgroundTask *task = NULL;
|
||||
ToolRegistry *tool_registry = NULL;
|
||||
|
||||
ToolInitializerCallbackRegistration *callback_registration = NULL;
|
||||
|
||||
if (tool_initializer == NULL)
|
||||
{
|
||||
return;
|
||||
|
|
@ -85,11 +174,18 @@ static void tool_initializer_unref_internal(
|
|||
&tool_initializer->mutex
|
||||
);
|
||||
|
||||
task = tool_initializer->task;
|
||||
tool_registry = tool_initializer->tool_registry;
|
||||
task =
|
||||
tool_initializer->task;
|
||||
|
||||
tool_registry =
|
||||
tool_initializer->tool_registry;
|
||||
|
||||
callback_registration =
|
||||
tool_initializer->callback_registration;
|
||||
|
||||
tool_initializer->task = NULL;
|
||||
tool_initializer->tool_registry = NULL;
|
||||
tool_initializer->callback_registration = NULL;
|
||||
tool_initializer->task_manager = NULL;
|
||||
tool_initializer->is_running = FALSE;
|
||||
|
||||
|
|
@ -101,6 +197,10 @@ static void tool_initializer_unref_internal(
|
|||
task
|
||||
);
|
||||
|
||||
tool_initializer_callback_registration_unref(
|
||||
callback_registration
|
||||
);
|
||||
|
||||
tool_registry_free(
|
||||
tool_registry
|
||||
);
|
||||
|
|
@ -771,8 +871,16 @@ static void tool_initializer_bootstrap_completed(
|
|||
ToolInitializer *tool_initializer =
|
||||
user_data;
|
||||
|
||||
const ToolInitializationSummary *summary =
|
||||
NULL;
|
||||
ToolInitializerCallbackRegistration *callback_registration = NULL;
|
||||
|
||||
BackgroundTaskState final_state;
|
||||
|
||||
const ToolInitializationSummary *task_summary = NULL;
|
||||
const ToolInitializationSummary *callback_summary = NULL;
|
||||
|
||||
ToolInitializationSummary summary_copy = {0};
|
||||
|
||||
GError *callback_error = NULL;
|
||||
|
||||
if (task == NULL ||
|
||||
tool_initializer == NULL)
|
||||
|
|
@ -780,33 +888,89 @@ static void tool_initializer_bootstrap_completed(
|
|||
return;
|
||||
}
|
||||
|
||||
if (background_task_get_state(
|
||||
task
|
||||
) == BACKGROUND_TASK_STATE_COMPLETED)
|
||||
{
|
||||
summary = background_task_get_result(
|
||||
final_state =
|
||||
background_task_get_state(
|
||||
task
|
||||
);
|
||||
|
||||
if (final_state == BACKGROUND_TASK_STATE_COMPLETED)
|
||||
{
|
||||
task_summary =
|
||||
background_task_get_result(
|
||||
task
|
||||
);
|
||||
|
||||
if (task_summary != NULL)
|
||||
{
|
||||
summary_copy =
|
||||
*task_summary;
|
||||
|
||||
callback_summary =
|
||||
&summary_copy;
|
||||
}
|
||||
}
|
||||
else if (final_state == BACKGROUND_TASK_STATE_FAILED)
|
||||
{
|
||||
callback_error =
|
||||
background_task_dup_error(
|
||||
task
|
||||
);
|
||||
}
|
||||
|
||||
g_mutex_lock(
|
||||
&tool_initializer->mutex
|
||||
);
|
||||
|
||||
if (summary != NULL)
|
||||
if (callback_summary != NULL)
|
||||
{
|
||||
tool_initializer->last_summary =
|
||||
*summary;
|
||||
summary_copy;
|
||||
|
||||
tool_initializer->has_last_summary =
|
||||
TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
tool_initializer->last_summary =
|
||||
(ToolInitializationSummary) {0};
|
||||
|
||||
tool_initializer->has_last_summary =
|
||||
FALSE;
|
||||
}
|
||||
|
||||
tool_initializer->is_running = FALSE;
|
||||
|
||||
callback_registration =
|
||||
tool_initializer_callback_registration_ref(
|
||||
tool_initializer->callback_registration
|
||||
);
|
||||
|
||||
g_mutex_unlock(
|
||||
&tool_initializer->mutex
|
||||
);
|
||||
|
||||
/*
|
||||
* Le callback utilisateur est toujours appelé hors du mutex.
|
||||
* Il peut donc consulter l’initialiseur ou remplacer son callback.
|
||||
*/
|
||||
if (callback_registration != NULL)
|
||||
{
|
||||
callback_registration->callback(
|
||||
tool_initializer,
|
||||
final_state,
|
||||
callback_summary,
|
||||
callback_error,
|
||||
callback_registration->user_data
|
||||
);
|
||||
}
|
||||
|
||||
tool_initializer_callback_registration_unref(
|
||||
callback_registration
|
||||
);
|
||||
|
||||
g_clear_error(
|
||||
&callback_error
|
||||
);
|
||||
}
|
||||
|
||||
GQuark tool_initializer_error_quark(void)
|
||||
|
|
@ -877,6 +1041,17 @@ void tool_initializer_free(
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Le propriétaire public abandonne l’initialiseur.
|
||||
* Aucun callback ne doit désormais utiliser son user_data.
|
||||
*/
|
||||
tool_initializer_set_completed_callback(
|
||||
tool_initializer,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
|
||||
task = tool_initializer_get_task(
|
||||
tool_initializer
|
||||
);
|
||||
|
|
@ -1031,16 +1206,16 @@ gboolean tool_initializer_start(
|
|||
|
||||
tool_initializer->is_running = FALSE;
|
||||
|
||||
g_mutex_unlock(
|
||||
&tool_initializer->mutex
|
||||
);
|
||||
|
||||
tool_initializer->last_summary =
|
||||
previous_summary;
|
||||
|
||||
tool_initializer->has_last_summary =
|
||||
previous_has_last_summary;
|
||||
|
||||
g_mutex_unlock(
|
||||
&tool_initializer->mutex
|
||||
);
|
||||
|
||||
tool_initializer_set_wrapped_error(
|
||||
error,
|
||||
TOOL_INITIALIZER_ERROR_TASK_REGISTRATION,
|
||||
|
|
@ -1175,6 +1350,77 @@ gboolean tool_initializer_start(
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
void tool_initializer_set_completed_callback(
|
||||
ToolInitializer *tool_initializer,
|
||||
ToolInitializerCompletedCallback callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy_notify
|
||||
)
|
||||
{
|
||||
ToolInitializerCallbackRegistration *new_registration = NULL;
|
||||
ToolInitializerCallbackRegistration *previous_registration = NULL;
|
||||
|
||||
if (callback != NULL)
|
||||
{
|
||||
new_registration =
|
||||
tool_initializer_callback_registration_new(
|
||||
callback,
|
||||
user_data,
|
||||
destroy_notify
|
||||
);
|
||||
}
|
||||
|
||||
if (tool_initializer == NULL)
|
||||
{
|
||||
tool_initializer_callback_registration_unref(
|
||||
new_registration
|
||||
);
|
||||
|
||||
/*
|
||||
* Aucun enregistrement n’a pu prendre possession des données.
|
||||
*/
|
||||
if (new_registration == NULL &&
|
||||
destroy_notify != NULL)
|
||||
{
|
||||
destroy_notify(
|
||||
user_data
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
g_mutex_lock(
|
||||
&tool_initializer->mutex
|
||||
);
|
||||
|
||||
previous_registration =
|
||||
tool_initializer->callback_registration;
|
||||
|
||||
tool_initializer->callback_registration =
|
||||
new_registration;
|
||||
|
||||
g_mutex_unlock(
|
||||
&tool_initializer->mutex
|
||||
);
|
||||
|
||||
tool_initializer_callback_registration_unref(
|
||||
previous_registration
|
||||
);
|
||||
|
||||
/*
|
||||
* callback == NULL signifie suppression.
|
||||
* Les éventuelles nouvelles données ne sont pas conservées.
|
||||
*/
|
||||
if (callback == NULL &&
|
||||
destroy_notify != NULL)
|
||||
{
|
||||
destroy_notify(
|
||||
user_data
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean tool_initializer_cancel(
|
||||
ToolInitializer *tool_initializer,
|
||||
GError **error
|
||||
|
|
|
|||
Binary file not shown.
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue