/* Chrysalide - Outil d'analyse de fichiers binaires
* gtkextstatusbar.h - prototypes pour la barre de statut améliorée
*
* Copyright (C) 2009-2013 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* OpenIDA is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* OpenIDA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Foobar. If not, see .
*/
#include "gtkextstatusbar.h"
#include
#include
/* ------------------------- GESTION EXTERIEURE DE LA BARRE ------------------------- */
/* Elément de statut */
typedef struct _bar_item
{
char *message; /* Message à afficher */
bool is_progressive; /* Utilisations de progression */
double value; /* Valeur courante */
size_t index; /* Valeur pour l'identifiant */
} bar_item;
/* Abstration d'une gestion de barre de statut (instance) */
struct _GtkExtStatusBar
{
GtkStatusbar bar; /* Présence obligatoire en 1er */
guint context; /* Nouvel identifiant */
guint cur_msg; /* Message courant */
GtkProgressBar *progress; /* Barre de progression */
bar_item *stack; /* Pile de statut de la barre */
size_t stack_size; /* Taille de la pile */
GMutex stack_access; /* Accès en à la pile */
};
/* Abstration d'une gestion de barre de statut (classe) */
struct _GtkExtStatusBarClass
{
GtkStatusbarClass parent_class; /* Présence obligatoire en 1er */
};
/* Initialise la classe des barres de statut améliorées. */
static void gtk_extended_status_bar_class_init(GtkExtStatusBarClass *);
/* Initialise une instance de barre de statut améliorée. */
static void gtk_extended_status_bar_init(GtkExtStatusBar *);
/* ----------------------- MISES A JOUR EN CONTEXTE PRINCIPAL ----------------------- */
/* Type de commande */
typedef enum _DelayedUpdateCmd
{
DUC_CHANGE_CONTENT, /* Elément ajouté ou retiré */
DUC_UPDATE_ACTIVITY /* Mise à jour de progression */
} DelayedUpdateCmd;
/* Transfert des commandes */
typedef struct _bar_update_info
{
GtkExtStatusBar *bar; /* Barre associée */
DelayedUpdateCmd cmd; /* Type de commande */
} bar_update_info;
/* Met à jour la partie graphique de la barre de statut. */
static gboolean gtk_extended_status_update(bar_update_info *);
/* Libère la mémoire occupée par la transmission. */
static void free_bar_update_info(bar_update_info *);
/* Place un nouveau message dans la barre de statut. */
static void _gtk_extended_status_bar_change_content(GtkExtStatusBar *);
/* Met à jour la barre de progression de la barre de statut. */
static void _gtk_extended_status_bar_update_activity(GtkExtStatusBar *);
/* ---------------------------------------------------------------------------------- */
/* GESTION EXTERIEURE DE LA BARRE */
/* ---------------------------------------------------------------------------------- */
/* Détermine le type de la barre de statut améliorée. */
G_DEFINE_TYPE(GtkExtStatusBar, gtk_extended_status_bar, GTK_TYPE_STATUSBAR)
/******************************************************************************
* *
* Paramètres : klass = classe GTK à initialiser. *
* *
* Description : Initialise la classe des barres de statut améliorées. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_extended_status_bar_class_init(GtkExtStatusBarClass *klass)
{
}
/******************************************************************************
* *
* Paramètres : bar = instance GTK à initialiser. *
* *
* Description : Initialise une instance de barre de statut améliorée. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_extended_status_bar_init(GtkExtStatusBar *bar)
{
bar->context = gtk_statusbar_get_context_id(GTK_STATUSBAR(bar), "");
bar->progress = GTK_PROGRESS_BAR(gtk_progress_bar_new());
gtk_widget_set_size_request(GTK_WIDGET(bar->progress), 200, -1);
gtk_progress_bar_set_fraction(bar->progress, 0.5);
gtk_progress_bar_set_text(bar->progress, "50%");
gtk_box_pack_start(GTK_BOX(bar), GTK_WIDGET(bar->progress), FALSE, FALSE, 4);
g_mutex_init(&bar->stack_access);
}
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Crée une nouvelle instance de barre de statut. *
* *
* Retour : Composant GTK mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *gtk_extended_status_bar_new(void)
{
return g_object_new(GTK_TYPE_EXT_STATUS_BAR, NULL);
}
/******************************************************************************
* *
* Paramètres : bar = barre de statut à manipuler. *
* message = message à afficher pour l'utilisateur. *
* progressive = utilisation de la barre de progression. *
* *
* Description : Place un nouveau message dans la barre de statut. *
* *
* Retour : Identifiant du nouveau statut défini. *
* *
* Remarques : - *
* *
******************************************************************************/
bstatus_id_t gtk_extended_status_bar_push(GtkExtStatusBar *bar, const char *message, bool progressive)
{
bstatus_id_t result; /* Identifiant à retourner */
size_t index; /* Indice du nouvel élément */
bar_update_info *info; /* Informations à mémoriser */
/* Mise à jour de la pile */
g_mutex_lock(&bar->stack_access);
bar->stack = (bar_item *)realloc(bar->stack, ++bar->stack_size * sizeof(bar_item));
index = bar->stack_size - 1;
bar->stack[index].message = strdup(message);
bar->stack[index].is_progressive = progressive;
bar->stack[index].value = 0.0;
bar->stack[index].index = index;
result = &bar->stack[index].index;
g_mutex_unlock(&bar->stack_access);
/* Mise à jour de l'affichage */
info = (bar_update_info *)calloc(1, sizeof(bar_update_info));
info->bar = bar;
g_object_ref(G_OBJECT(bar));
info->cmd = DUC_CHANGE_CONTENT;
gdk_threads_add_idle_full(G_PRIORITY_HIGH_IDLE, (GSourceFunc)gtk_extended_status_update,
info, (GDestroyNotify)free_bar_update_info);
return result;
}
/******************************************************************************
* *
* Paramètres : bar = barre de statut à manipuler. *
* id = identifiant du message concerné. *
* value = valeur actuelle de la progression. *
* *
* Description : Met à jour la barre de progression de la barre de statut. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void gtk_extended_status_bar_update_activity(GtkExtStatusBar *bar, bstatus_id_t id, double value)
{
bar_update_info *info; /* Informations à mémoriser */
/* Mise à jour de la pile */
g_mutex_lock(&bar->stack_access);
bar->stack[*id].value = value;
g_mutex_unlock(&bar->stack_access);
/* Mise à jour de l'affichage */
info = (bar_update_info *)calloc(1, sizeof(bar_update_info));
info->bar = bar;
g_object_ref(G_OBJECT(bar));
info->cmd = DUC_UPDATE_ACTIVITY;
gdk_threads_add_idle_full(G_PRIORITY_HIGH_IDLE, (GSourceFunc)gtk_extended_status_update,
info, (GDestroyNotify)free_bar_update_info);
}
/******************************************************************************
* *
* Paramètres : bar = barre de statut à manipuler. *
* id = identifiant du statut à supprimer. *
* *
* Description : Retire de la barre un statut, visible ou non. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void gtk_extended_status_bar_remove(GtkExtStatusBar *bar, bstatus_id_t id)
{
size_t index; /* Indice de l'élément visé */
size_t i; /* Boucle de parcours */
bar_update_info *info; /* Informations à mémoriser */
/* Mise à jour de la pile */
g_mutex_lock(&bar->stack_access);
index = *id;
free(bar->stack[index].message);
if ((index + 1) < bar->stack_size)
{
memmove(&bar->stack[index], &bar->stack[index + 1],
(bar->stack_size - index - 1) * sizeof(bar_item));
for (i = index; i < bar->stack_size; i++)
bar->stack[i].index = i;
}
bar->stack = (bar_item *)realloc(bar->stack, --bar->stack_size * sizeof(bar_item));
g_mutex_unlock(&bar->stack_access);
/* Mise à jour de l'affichage */
info = (bar_update_info *)calloc(1, sizeof(bar_update_info));
info->bar = bar;
g_object_ref(G_OBJECT(bar));
info->cmd = DUC_CHANGE_CONTENT;
gdk_threads_add_idle_full(G_PRIORITY_HIGH_IDLE, (GSourceFunc)gtk_extended_status_update,
info, (GDestroyNotify)free_bar_update_info);
}
/* ---------------------------------------------------------------------------------- */
/* MISES A JOUR EN CONTEXTE PRINCIPAL */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : info = informations à consulter pour l'opération. *
* *
* Description : Met à jour la partie graphique de la barre de statut. *
* *
* Retour : FALSE pour faire disparaître la mise à jour ensuite. *
* *
* Remarques : - *
* *
******************************************************************************/
static gboolean gtk_extended_status_update(bar_update_info *info)
{
switch (info->cmd)
{
case DUC_CHANGE_CONTENT:
_gtk_extended_status_bar_change_content(info->bar);
/*break;*/
case DUC_UPDATE_ACTIVITY:
_gtk_extended_status_bar_update_activity(info->bar);
break;
}
return FALSE;
}
/******************************************************************************
* *
* Paramètres : info = informations à libérer de la mémoire. *
* *
* Description : Libère la mémoire occupée par la transmission. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void free_bar_update_info(bar_update_info *info)
{
g_object_unref(G_OBJECT(info->bar));
free(info);
}
/******************************************************************************
* *
* Paramètres : bar = barre de statut à manipuler. *
* *
* Description : Place un nouveau message dans la barre de statut. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void _gtk_extended_status_bar_change_content(GtkExtStatusBar *bar)
{
size_t top; /* Indice de l'élément visé */
g_mutex_lock(&bar->stack_access);
if (bar->cur_msg > 0)
gtk_statusbar_remove(GTK_STATUSBAR(bar), bar->context, bar->cur_msg);
if (bar->stack_size == 0)
gtk_widget_hide(GTK_WIDGET(bar->progress));
else
{
top = bar->stack_size - 1;
bar->cur_msg = gtk_statusbar_push(GTK_STATUSBAR(bar), bar->context,
bar->stack[top].message);
if (bar->stack[top].is_progressive)
gtk_widget_show(GTK_WIDGET(bar->progress));
else
gtk_widget_hide(GTK_WIDGET(bar->progress));
}
g_mutex_unlock(&bar->stack_access);
}
/******************************************************************************
* *
* Paramètres : bar = barre de statut à manipuler. *
* *
* Description : Met à jour la barre de progression de la barre de statut. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void _gtk_extended_status_bar_update_activity(GtkExtStatusBar *bar)
{
size_t top; /* Indice de l'élément visé */
double value; /* Valeur à prendre en compte */
gchar percent[5]; /* Pourcentage en version txt. */
g_mutex_lock(&bar->stack_access);
if (bar->stack_size > 0)
{
top = bar->stack_size - 1;
if (bar->stack[top].is_progressive)
{
value = bar->stack[top].value;
if (value != 1.0 && value - gtk_progress_bar_get_fraction(bar->progress) < 0.01)
goto gesbua_exit;
g_snprintf(percent, 5, "%.0f%%", value * 100);
gtk_progress_bar_set_fraction(bar->progress, value);
gtk_progress_bar_set_text(bar->progress, percent);
}
}
gesbua_exit:
g_mutex_unlock(&bar->stack_access);
}