diff options
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/core/panels.c | 4 | ||||
-rw-r--r-- | src/gui/editor.c | 109 | ||||
-rw-r--r-- | src/gui/panels/Makefile.am | 19 | ||||
-rw-r--r-- | src/gui/panels/gresource.xml | 6 | ||||
-rw-r--r-- | src/gui/panels/panel-int.h | 10 | ||||
-rw-r--r-- | src/gui/panels/panel.c | 6 | ||||
-rw-r--r-- | src/gui/panels/regedit.c | 2 | ||||
-rw-r--r-- | src/gui/panels/welcome.c | 865 | ||||
-rw-r--r-- | src/gui/panels/welcome.h | 68 | ||||
-rw-r--r-- | src/gui/panels/welcome.ui | 245 |
10 files changed, 1306 insertions, 28 deletions
diff --git a/src/gui/core/panels.c b/src/gui/core/panels.c index d8565f4..9dcb199 100644 --- a/src/gui/core/panels.c +++ b/src/gui/core/panels.c @@ -33,6 +33,7 @@ #include "../panels/regedit.h" #include "../panels/strings.h" #include "../panels/symbols.h" +#include "../panels/welcome.h" #include "../../core/params.h" #include "../../gtkext/gtkdockable.h" @@ -62,6 +63,9 @@ void load_main_panels(GObject *ref) config = get_main_configuration(); + item = g_welcome_panel_new(); + register_panel_item(item, ref, config); + item = g_log_panel_new(); register_panel_item(item, ref, config); diff --git a/src/gui/editor.c b/src/gui/editor.c index 926201a..3723bd8 100644 --- a/src/gui/editor.c +++ b/src/gui/editor.c @@ -39,6 +39,7 @@ #include "core/core.h" #include "core/panels.h" #include "panels/panel.h" +#include "panels/welcome.h" #include "tb/portions.h" #include "tb/source.h" #include "../analysis/project.h" @@ -158,7 +159,7 @@ static void update_path_of_paned_nodes(panel_node *, const char *, const char *) static size_t compute_path_common_length(const panel_node *, const char *); /* Place au bon endroit un panneau donné. */ -static void insert_item_as_panel_node(GPanelItem *, panel_node *, const char *, size_t); +static panel_node *insert_item_as_panel_node(GPanelItem *, panel_node *, const char *, size_t); /* Tente de mettre la main sur une station d'accueil. */ static panel_node *find_node_for_station(panel_node *, GtkWidget *); @@ -788,18 +789,18 @@ static size_t compute_path_common_length(const panel_node *node, const char *tar * * * Description : Place au bon endroit un panneau donné. * * * -* Retour : - * +* Retour : Noeud final inséré dans la liste. * * * * Remarques : - * * * ******************************************************************************/ -static void insert_item_as_panel_node(GPanelItem *item, panel_node *node, const char *path, size_t consumed) +static panel_node *insert_item_as_panel_node(GPanelItem *item, panel_node *node, const char *path, size_t consumed) { + panel_node *result; /* Noeud ultime à renvoyer */ char div; /* Division demandée */ bool horiz; /* Traduction en composant */ bool first; /* Point d'insertion */ - panel_node *new; /* Nouveau noeud créé */ size_t common1; /* Tron common avec le côté #1 */ size_t common2; /* Tron common avec le côté #2 */ @@ -813,7 +814,10 @@ static void insert_item_as_panel_node(GPanelItem *item, panel_node *node, const { /* Le parcours s'arrête ici ! */ if (strcmp(node->path, path) == 0) + { gtk_dock_station_add_dockable(GTK_DOCK_STATION(node->station), GTK_DOCKABLE(item)); + result = node; + } /* On ne peut aller plus loin, on doit diviser... */ else @@ -828,9 +832,9 @@ static void insert_item_as_panel_node(GPanelItem *item, panel_node *node, const switch_panel_node_into_paned(node, horiz, !first); - new = create_simple_panel_node_for_item(item, path); + result = create_simple_panel_node_for_item(item, path); - attach_panel_node_to_paned(node, new, first); + attach_panel_node_to_paned(node, result, first); fprintf(stderr, "1# [%p] widget = %p --- split :: %p // %p\n", @@ -857,10 +861,10 @@ static void insert_item_as_panel_node(GPanelItem *item, panel_node *node, const if (common1 > 0 || common2 > 0) { if (common1 > common2) - insert_item_as_panel_node(item, node->first, path, common1); + result = insert_item_as_panel_node(item, node->first, path, common1); else - insert_item_as_panel_node(item, node->second, path, common2); + result = insert_item_as_panel_node(item, node->second, path, common2); } @@ -875,9 +879,9 @@ static void insert_item_as_panel_node(GPanelItem *item, panel_node *node, const switch_panel_node_into_paned(node, horiz, !first); - new = create_simple_panel_node_for_item(item, path); + result = create_simple_panel_node_for_item(item, path); - attach_panel_node_to_paned(node, new, first); + attach_panel_node_to_paned(node, result, first); fprintf(stderr, "2# [%p] split :: %p-%p // %p-%p\n", node, @@ -888,6 +892,8 @@ static void insert_item_as_panel_node(GPanelItem *item, panel_node *node, const } + return result; + } @@ -1047,7 +1053,7 @@ static void delete_panel_node(panel_node *node) /****************************************************************************** * * -* Paramètres : item = composant à retirer de l'affichage. * +* Paramètres : panel = composant à placer dans l'affichage. * * unused = adresse non utilisée ici. * * * * Description : Réagit à une demande de placement d'un panneau d'affichage. * @@ -1058,28 +1064,53 @@ static void delete_panel_node(panel_node *node) * * ******************************************************************************/ -void on_panel_item_dock_request(GPanelItem *item, void *unused) +void on_panel_item_dock_request(GPanelItem *panel, void *unused) { const char *path; /* Chemin d'accès */ + panel_node *node; /* Noeud à supprimer */ + const char *name; /* Nom du dernier panneau */ + GPanelItem *welcome; /* Panneau d'accueil */ - path = gtk_panel_item_get_path(item); + path = gtk_panel_item_get_path(panel); /* Tout est à faire... */ if (_nodes == NULL) { - _nodes = create_simple_panel_node_for_item(item, path); + _nodes = create_simple_panel_node_for_item(panel, path); gtk_container_add(GTK_CONTAINER(_support), _nodes->widget); } - else insert_item_as_panel_node(item, _nodes, path, 0); + else + { + node = insert_item_as_panel_node(panel, _nodes, path, 0); + + if (strncmp(node->path, "N", 1) == 0) + { + name = g_editor_item_get_name(G_EDITOR_ITEM(panel)); + + if (strcmp(name, PANEL_WELCOME_ID) != 0) + { + welcome = get_panel_item_by_name(PANEL_WELCOME_ID); + + if (!g_welcome_panel_get_user_origin(G_WELCOME_PANEL(welcome))) + { + /* Equivalent d'un appel "g_panel_item_undock(welcome)", avec effet immédiat */ + on_panel_item_undock_request(welcome, NULL); + } + + } + + } + + } - g_panel_item_set_dock_status(item, true); + g_panel_item_set_dock_status(panel, true); } /****************************************************************************** * * -* Paramètres : item = composant à retirer de l'affichage. * +* Paramètres : panel = composant à retirer de l'affichage. * * unused = adresse non utilisée ici. * * * * Description : Réagit à une demande de suppression d'un panneau d'affichage.* @@ -1090,25 +1121,53 @@ void on_panel_item_dock_request(GPanelItem *item, void *unused) * * ******************************************************************************/ -void on_panel_item_undock_request(GPanelItem *item, void *unused) +void on_panel_item_undock_request(GPanelItem *panel, void *unused) { GtkWidget *station; /* Support courant */ + GtkNotebook *notebook; /* Version parente de station */ panel_node *node; /* Noeud à supprimer */ + bool allowed; /* Fermture permise ? */ + const char *name; /* Nom du dernier panneau */ + GPanelItem *welcome; /* Panneau d'accueil */ + + gtk_dockable_decompose(GTK_DOCKABLE(panel), &station); + + notebook = GTK_NOTEBOOK(station); - gtk_dockable_decompose(GTK_DOCKABLE(item), &station); + node = find_node_for_station(_nodes, station); + assert(node != NULL); - gtk_dock_station_remove_dockable(GTK_DOCK_STATION(station), GTK_DOCKABLE(item)); + allowed = true; - if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(station)) == 0) + if (strcmp(node->path, "N") == 0 && gtk_notebook_get_n_pages(notebook) == 1) { - node = find_node_for_station(_nodes, station); - assert(node != NULL); + name = g_editor_item_get_name(G_EDITOR_ITEM(panel)); + + if (strcmp(name, PANEL_WELCOME_ID) == 0) + allowed = false; + + else + { + welcome = get_panel_item_by_name(PANEL_WELCOME_ID); + g_welcome_panel_set_user_origin(G_WELCOME_PANEL(welcome), false); + + /* Equivalent d'un appel "g_panel_item_dock(welcome)", avec effet immédiat */ + on_panel_item_dock_request(welcome, NULL); - delete_panel_node(node); + } } - g_panel_item_set_dock_status(item, false); + if (allowed) + { + gtk_dock_station_remove_dockable(GTK_DOCK_STATION(station), GTK_DOCKABLE(panel)); + + if (gtk_notebook_get_n_pages(notebook) == 0) + delete_panel_node(node); + + g_panel_item_set_dock_status(panel, false); + + } } diff --git a/src/gui/panels/Makefile.am b/src/gui/panels/Makefile.am index 4746210..929aef1 100644 --- a/src/gui/panels/Makefile.am +++ b/src/gui/panels/Makefile.am @@ -1,6 +1,11 @@ +BUILT_SOURCES = resources.h resources.c + noinst_LTLIBRARIES = libguipanels.la +UI_FILES = \ + welcome.ui + libguipanels_la_SOURCES = \ bookmarks.h bookmarks.c \ glance.h glance.c \ @@ -8,8 +13,10 @@ libguipanels_la_SOURCES = \ log.h log.c \ panel.h panel.c \ regedit.h regedit.c \ + resources.h resources.c \ strings.h strings.c \ - symbols.h symbols.c + symbols.h symbols.c \ + welcome.h welcome.c libguipanels_la_LDFLAGS = @@ -19,3 +26,13 @@ AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) SUBDIRS = + + +resources.c: gresource.xml $(UI_FILES) + glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name gui_panels gresource.xml + +resources.h: gresource.xml + glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-header --c-name gui_panels gresource.xml + + +CLEANFILES = resources.h resources.c diff --git a/src/gui/panels/gresource.xml b/src/gui/panels/gresource.xml new file mode 100644 index 0000000..58d47e2 --- /dev/null +++ b/src/gui/panels/gresource.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gresources> + <gresource prefix="/org/chrysalide/gui/panels"> + <file compressed="true">welcome.ui</file> + </gresource> +</gresources> diff --git a/src/gui/panels/panel-int.h b/src/gui/panels/panel-int.h index 7e44275..4b0ef0c 100644 --- a/src/gui/panels/panel-int.h +++ b/src/gui/panels/panel-int.h @@ -37,6 +37,13 @@ +/* Place un panneau dans l'ensemble affiché. */ +typedef void (* ack_dock_process_fc) (GPanelItem *item); + +/* Supprime un panneau de l'ensemble affiché. */ +typedef void (* ack_undock_process_fc) (GPanelItem *item); + + /* Elément réactif pour panneaux de l'éditeur (instance) */ struct _GPanelItem { @@ -63,7 +70,8 @@ struct _GPanelItemClass bool unique; /* Panneau instanciable ? */ const char *bindings; /* Raccourci clavier éventuel */ - //GtkBin *first; /* Elément racine */ + ack_dock_process_fc ack_dock; /* Prise en compte d'accroche */ + ack_undock_process_fc ack_undock; /* Prise en compte de décroche */ /* Signaux */ diff --git a/src/gui/panels/panel.c b/src/gui/panels/panel.c index ee0c102..edf57d3 100644 --- a/src/gui/panels/panel.c +++ b/src/gui/panels/panel.c @@ -474,6 +474,9 @@ void g_panel_item_dock(GPanelItem *item) g_signal_emit_by_name(item, "dock-request"); + if (G_PANEL_ITEM_GET_CLASS(item)->ack_dock != NULL) + G_PANEL_ITEM_GET_CLASS(item)->ack_dock(item); + } @@ -543,4 +546,7 @@ void g_panel_item_undock(GPanelItem *item) g_signal_emit_by_name(item, "undock-request"); + if (G_PANEL_ITEM_GET_CLASS(item)->ack_undock != NULL) + G_PANEL_ITEM_GET_CLASS(item)->ack_undock(item); + } diff --git a/src/gui/panels/regedit.c b/src/gui/panels/regedit.c index 5e224ec..66f0330 100644 --- a/src/gui/panels/regedit.c +++ b/src/gui/panels/regedit.c @@ -225,7 +225,7 @@ static void g_regedit_panel_init(GRegeditPanel *panel) pitem->personality = PIP_SINGLETON; pitem->lname = _("Configuration parameters"); - pitem->dock_at_startup = true; + pitem->dock_at_startup = false; pitem->path = strdup("N"); /* Représentation graphique */ diff --git a/src/gui/panels/welcome.c b/src/gui/panels/welcome.c new file mode 100644 index 0000000..209419f --- /dev/null +++ b/src/gui/panels/welcome.c @@ -0,0 +1,865 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * welcome.c - panneau d'accueil par défaut + * + * Copyright (C) 2016 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "welcome.h" + + +#include <assert.h> +#include <malloc.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + + +#include <config.h> +#include <i18n.h> + + +#include "panel-int.h" +#include "../../common/cpp.h" +#include "../../common/io.h" +#include "../../common/net.h" +#include "../../common/shuffle.h" +#include "../../core/params.h" +#include "../../gtkext/support.h" + + + +/* Panneau d'accueil par défaut (instance) */ +struct _GWelcomePanel +{ + GPanelItem parent; /* A laisser en premier */ + + GtkBuilder *builder; /* Constructeur utilisé */ + cairo_surface_t *background; /* Fond pour astuces */ + + char **tips; /* Liste de toutes les astuces */ + size_t count; /* Quantité d'astuces */ + size_t current; /* Indice de l'astuce courante */ + + bool uorigin; /* Origine de l'affichage */ + +}; + +/* Panneau d'accueil par défaut (classe) */ +struct _GWelcomePanelClass +{ + GPanelItemClass parent; /* A laisser en premier */ + +}; + + +/* Colonnes de la liste des messages */ +typedef enum _RecentProjectColumn +{ + RPC_VALID, /* Validité de l'entrée */ + RPC_FULLPATH, /* Chemin d'accès à un projet */ + + RPC_COUNT /* Nombre de colonnes */ + +} RecentProjectColumn; + + +/* Initialise la classe des panneaux d'accueil par défaut. */ +static void g_welcome_panel_class_init(GWelcomePanelClass *); + +/* Initialise une instance de panneau d'accueil par défaut. */ +static void g_welcome_panel_init(GWelcomePanel *); + +/* Supprime toutes les références externes. */ +static void g_welcome_panel_dispose(GWelcomePanel *); + +/* Procède à la libération totale de la mémoire. */ +static void g_welcome_panel_finalize(GWelcomePanel *); + +/* Place un panneau dans l'ensemble affiché. */ +static void g_welcome_panel_dock(GWelcomePanel *); + +/* Charge l'ensemble des astuces. */ +static void g_welcome_panel_load_tips(GWelcomePanel *); + +/* Assure le dessin du fond de la bulle d'astuce. */ +static gboolean on_tip_background_draw(GtkWidget *, cairo_t *, GWelcomePanel *); + +/* Réagit à la demande d'étude d'un nouveau binaire. */ +static void on_new_binary_clicked(GtkButton *, GWelcomePanel *); + +/* Actualise au besoin la liste des projets récents. */ +static void on_recent_list_changed(GtkRecentManager *, GWelcomePanel *); + +/* Recharge une liste à jour des projets récents. */ +static void g_welcome_panel_reload_project_list(GWelcomePanel *, GtkRecentManager *); + +/* Réagit à une sélection décidée d'un projet particulier. */ +static void on_row_activated_for_projects(GtkTreeView *, GtkTreePath *, GtkTreeViewColumn *, GWelcomePanel *); + +/* Enregistre les conditions d'affichage du panneau d'accueil. */ +static void on_startup_toggled(GtkToggleButton *, GWelcomePanel *); + +/* Consulte les versions existantes et affiche une conclusion. */ +static void g_welcome_panel_check_version(GWelcomePanel *); + +/* Affiche l'astuce précédente dans la liste globale. */ +static void on_tip_previous_clicked(GtkButton *, GWelcomePanel *); + +/* Affiche l'astuce suivante dans la liste globale. */ +static void on_tip_next_clicked(GtkButton *, GWelcomePanel *); + +/* Actualise l'affichage des astuces. */ +static void g_welcome_panel_refresh_tip(GWelcomePanel *); + + +/* Indique le type défini pour un panneau d'accueil. */ +G_DEFINE_TYPE(GWelcomePanel, g_welcome_panel, G_TYPE_PANEL_ITEM); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des panneaux d'accueil par défaut. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_welcome_panel_class_init(GWelcomePanelClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GPanelItemClass *parent; /* Version parente de classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_welcome_panel_dispose; + object->finalize = (GObjectFinalizeFunc)g_welcome_panel_finalize; + + parent = G_PANEL_ITEM_CLASS(klass); + + parent->ack_dock = (ack_undock_process_fc)g_welcome_panel_dock; + +} + + +/****************************************************************************** +* * +* Paramètres : panel = instance à initialiser. * +* * +* Description : Initialise une instance de panneau d'accueil par défaut. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_welcome_panel_init(GWelcomePanel *panel) +{ + GEditorItem *base; /* Version basique d'instance */ + GPanelItem *pitem; /* Version parente du panneau */ + GtkTreeView *treeview; /* Affichage de la liste */ + GtkCellRenderer *renderer; /* Moteur de rendu de colonne */ + GtkTreeViewColumn *column; /* Colonne de la liste */ + GtkToggleButton *button; /* Bouton à bascule à traiter */ + bool state; /* Etat de la coche à définir */ + gchar *filename; /* Chemin d'accès à une image */ + + /* Eléments de base */ + + base = G_EDITOR_ITEM(panel); + + base->name = PANEL_WELCOME_ID; + + pitem = G_PANEL_ITEM(panel); + + pitem->personality = PIP_SINGLETON; + pitem->lname = _("Welcome"); + pitem->dock_at_startup = true; + pitem->path = strdup("N"); + + panel->uorigin = !pitem->dock_at_startup; + + /* Représentation graphique */ + + panel->builder = gtk_builder_new_from_resource("/org/chrysalide/gui/panels/welcome.ui"); + + base->widget = GTK_WIDGET(gtk_builder_get_object(panel->builder, "box")); + g_object_ref(G_OBJECT(base->widget)); + gtk_widget_unparent(base->widget); + + /* Liste des projets récents */ + + treeview = GTK_TREE_VIEW(gtk_builder_get_object(panel->builder, "treeview")); + + column = gtk_tree_view_column_new(); + gtk_tree_view_append_column(treeview, column); + gtk_tree_view_set_expander_column(treeview, column); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, renderer, TRUE); + gtk_tree_view_column_add_attribute(column, renderer, "markup", RPC_FULLPATH); + + /* Affichage au démarrage ? */ + + button = GTK_TOGGLE_BUTTON(gtk_builder_get_object(panel->builder, "startup")); + + g_generic_config_get_value(get_main_configuration(), MPK_WELCOME_STARTUP, &state); + + gtk_toggle_button_set_active(button, state); + + /* Chargement de l'image de fond */ + + filename = find_pixmap_file("tipoftheday.png"); + + panel->background = cairo_image_surface_create_from_png(filename); + + g_free(filename); + + /* Connexion des signaux */ + + gtk_builder_add_callback_symbols(panel->builder, + "on_tip_background_draw", G_CALLBACK(on_tip_background_draw), + "on_new_binary_clicked", G_CALLBACK(on_new_binary_clicked), + "on_row_activated_for_projects", G_CALLBACK(on_row_activated_for_projects), + "on_startup_toggled", G_CALLBACK(on_startup_toggled), + "on_tip_previous_clicked", G_CALLBACK(on_tip_previous_clicked), + "on_tip_next_clicked", G_CALLBACK(on_tip_next_clicked), + NULL); + + gtk_builder_connect_signals(panel->builder, panel); + +} + + +/****************************************************************************** +* * +* Paramètres : panel = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_welcome_panel_dispose(GWelcomePanel *panel) +{ + g_object_unref(G_OBJECT(panel->builder)); + + free(panel->tips); + + G_OBJECT_CLASS(g_welcome_panel_parent_class)->dispose(G_OBJECT(panel)); + +} + + +/****************************************************************************** +* * +* Paramètres : panel = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_welcome_panel_finalize(GWelcomePanel *panel) +{ + cairo_surface_destroy(panel->background); + + G_OBJECT_CLASS(g_welcome_panel_parent_class)->finalize(G_OBJECT(panel)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée un panneau d'accueil par défaut. * +* * +* Retour : Adresse de la structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GPanelItem *g_welcome_panel_new(void) +{ + GWelcomePanel *result; /* Structure à retourner */ + GtkRecentManager *manager; /* Gestionnaire global */ + + result = g_object_new(G_TYPE_WELCOME_PANEL, NULL); + + manager = get_projects_manager(); + + g_signal_connect(manager, "changed", G_CALLBACK(on_recent_list_changed), result); + + g_welcome_panel_reload_project_list(result, manager); + + g_welcome_panel_load_tips(result); + + g_welcome_panel_check_version(result); + + return G_PANEL_ITEM(result); + +} + + +/****************************************************************************** +* * +* Paramètres : panel = composant à présenter à l'affichage. * +* * +* Description : Place un panneau dans l'ensemble affiché. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_welcome_panel_dock(GWelcomePanel *panel) +{ + g_welcome_panel_set_user_origin(panel, true); + +} + + +/****************************************************************************** +* * +* Paramètres : panel = panneau d'accueil à mettre à jour. * +* * +* Description : Charge l'ensemble des astuces. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_welcome_panel_load_tips(GWelcomePanel *panel) +{ + size_t i; /* Boucle de parcours */ + + char *tips[] = { + + _("There is no need to install Chrysalide on your system if you only want to give it a try.\n\n" + "Just compile the source code and run the program from there."), + + _("Chrysalide can be used in external Python scripts by setting PYTHONPATH to the directory " + "containing the 'pychrysalide.so' file. For instance:\n\n" + " cd plugins/pychrysa/.libs/\n" + " export PYTHONPATH=$PWD\n\n" + "Then run the interpreter suitable to your configuration (debug or release):\n\n" + " python3-dbg -c 'import pychrysalide ; print(pychrysalide.mod_version())'"), + + _("All the configuration files for chrysalide are located in $HOME/.config/chrysalide/.") + + }; + + panel->count = ARRAY_SIZE(tips); + + panel->tips = (char **)calloc(panel->count, sizeof(char *)); + + for (i = 0; i < panel->count; i++) + panel->tips[i] = tips[i]; + + shuffle(panel->tips, panel->count, sizeof(char *)); + + panel->current = 0; + + g_welcome_panel_refresh_tip(panel); + +} + + +/****************************************************************************** +* * +* Paramètres : widget = composant graphique à redessiner. * +* cr = contexte graphique à utiliser. * +* panel = panneau associé comportant des informations utiles. * +* * +* Description : Assure le dessin du fond de la bulle d'astuce. * +* * +* Retour : FALSE pour poursuivre la propagation de l'événement. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static gboolean on_tip_background_draw(GtkWidget *widget, cairo_t *cr, GWelcomePanel *panel) +{ + int wgt_width; /* Largeur disponible totale */ + int wgt_height; /* Hauteur disponible totale */ + int img_width; /* Largeur de l'image de fond */ + int img_height; /* Hauteur de l'image de fond */ + double scale; /* Echelle à appliquer */ + + if (cairo_surface_status(panel->background) == CAIRO_STATUS_SUCCESS) + { + wgt_width = gtk_widget_get_allocated_width(widget); + wgt_height = gtk_widget_get_allocated_height(widget); + + img_width = cairo_image_surface_get_width(panel->background); + img_height = cairo_image_surface_get_height(panel->background); + + scale = wgt_height / (2.0 * img_height); + + cairo_scale(cr, scale, scale); + + cairo_set_source_surface(cr, panel->background, + (wgt_width / scale) - img_width, + ((wgt_height / scale) - img_height) / 2); + + cairo_paint(cr); + + } + + return FALSE; + +} + + +/****************************************************************************** +* * +* Paramètres : button = bouton impliqué dans la procédure. * +* panel = panneau associé comportant des informations utiles. * +* * +* Description : Réagit à la demande d'étude d'un nouveau binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_new_binary_clicked(GtkButton *button, GWelcomePanel *panel) +{ + GObject *ref; /* Espace de référencements */ + GtkMenuItem *item; /* Elément de menu simulé */ + + ref = g_editor_item_get_global_ref(G_EDITOR_ITEM(panel)); + + item = GTK_MENU_ITEM(g_object_get_data(ref, "mnu_project_add_binary")); + + gtk_menu_item_activate(item); + +} + + +/****************************************************************************** +* * +* Paramètres : manager = gestion de fichiers récemment utilisés. * +* panel = panneau associé comportant des informations utiles.* +* * +* Description : Actualise au besoin la liste des projets récents. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_recent_list_changed(GtkRecentManager *manager, GWelcomePanel *panel) +{ + g_welcome_panel_reload_project_list(panel, manager); + +} + + +/****************************************************************************** +* * +* Paramètres : panel = panneau comportant des informations utiles. * +* manager = gestion de fichiers récemment utilisés. * +* * +* Description : Recharge une liste à jour des projets récents. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_welcome_panel_reload_project_list(GWelcomePanel *panel, GtkRecentManager *manager) +{ + GtkListStore *store; /* Modèle de gestion */ + bool empty; /* Liste vide ? */ + GList *recents; /* Liste des fichiers récents */ + GList *recent; /* Elément à traiter */ + GtkRecentInfo *info; /* Informations sur l'élément */ + GtkTreeIter iter; /* Point d'insertion */ + + /* Réinitialisation */ + + store = GTK_LIST_STORE(gtk_builder_get_object(panel->builder, "store")); + + gtk_list_store_clear(store); + + empty = true; + + /* Chargement */ + + recents = gtk_recent_manager_get_items(manager); + + if (recents != NULL) + { + for (recent = g_list_first(recents); recent != NULL; recent = g_list_next(recent)) + { + info = recent->data; + + if (strcmp(gtk_recent_info_get_mime_type(info), "application/chrysalide.project") == 0) + { + gtk_list_store_append(store, &iter); + + gtk_list_store_set(store, &iter, + RPC_VALID, true, + RPC_FULLPATH, gtk_recent_info_get_uri_display(info), + -1); + + empty = false; + + } + + gtk_recent_info_unref(info); + + } + + g_list_free(recents); + + } + + /* Indication par défaut */ + if (empty) + { + gtk_list_store_append(store, &iter); + + gtk_list_store_set(store, &iter, + RPC_VALID, false, + RPC_FULLPATH, _("<i>(No recent project)</i>"), + -1); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : treeview = liste graphique concernée par la procédure. * +* path = chemin d'accès à la ligne sélectionnée. * +* column = colonne concernée par la sélection. * +* panel = panneau associé avec des informations utiles. * +* * +* Description : Réagit à une sélection décidée d'un projet particulier. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_row_activated_for_projects(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, GWelcomePanel *panel) +{ + GtkTreeModel *model; /* Modèle de gestion */ + GtkTreeIter iter; /* Point de la consultation */ + gboolean valid; /* Validité de l'entrée */ + gchar *filename; /* Chemin d'accès au projet */ + GObject *ref; /* Espace de référencements */ + GStudyProject *project; /* Nouveau projet à ouvrir */ + + model = gtk_tree_view_get_model(treeview); + + if (gtk_tree_model_get_iter(model, &iter, path)) + { + gtk_tree_model_get(model, &iter, RPC_VALID, &valid, RPC_FULLPATH, &filename, -1); + + if (valid) + { + ref = g_editor_item_get_global_ref(G_EDITOR_ITEM(panel)); + + project = g_study_project_open(ref, filename); + + if (project != NULL) + { + set_current_project(project); + + push_project_into_recent_list(project); + + } + + g_free(filename); + + } + + } + +} + + +/****************************************************************************** +* * +* Paramètres : button = bouton de défilement des astuces activé; * +* panel = panneau associé comportant des informations utiles. * +* * +* Description : Enregistre les conditions d'affichage du panneau d'accueil. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_startup_toggled(GtkToggleButton *button, GWelcomePanel *panel) +{ + g_generic_config_set_value(get_main_configuration(), + MPK_WELCOME_STARTUP, gtk_toggle_button_get_active(button)); + +} + + +/****************************************************************************** +* * +* Paramètres : panel = panneau d'accueil à mettre à jour. * +* * +* Description : Consulte les versions existantes et affiche une conclusion. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_welcome_panel_check_version(GWelcomePanel *panel) +{ + bool skip; /* Saut de la vérification */ + bool unknown; /* Impossibilité de comparaison*/ + int current; /* Version courante */ + int sock; /* Canal de communication */ + bool status; /* Bilan d'une communication */ + char buffer[1024]; /* Tampon de réception */ + size_t got; /* Quantité de données reçues */ + char *version; /* Version récupérée */ + int available; /* Version disponible */ + GtkLabel *label; /* Etiquette à éditer */ + char *msg; /* Message à faire paraître */ + + g_generic_config_get_value(get_main_configuration(), MPK_WELCOME_CHECK, &skip); + skip = !skip; + + unknown = true; + + current = atoi(VERSION); + + if (skip) goto check_process; + + /* Recherche en ligne */ + + sock = connect_via_tcp("www.chrysalide.re", "80", NULL); + if (sock == -1) goto check_process; + +#define REQUEST "GET /version.last HTTP/1.1\r\nHost: www.chrysalide.re\r\n\r\n" + + status = safe_send(sock, REQUEST, strlen(REQUEST), 0); + if (!status) goto check_done; + + status = recv_all(sock, buffer, sizeof(buffer), &got); + if (!status) goto check_done; + + version = strstr(buffer, "\r\n\r\n"); + + if (version != NULL) + { + available = atoi(version + 4); + + unknown = false; + + } + + check_done: + + close(sock); + + check_process: + + /* Affichage */ + + label = GTK_LABEL(gtk_builder_get_object(panel->builder, "version")); + + if (skip) + asprintf(&msg, + "Your version is: <b>%d</b>\n\n" \ + "Automatic version check is disabled.", + current); + + else + { + if (unknown) + asprintf(&msg, + "Your version is: <b>%d</b>\n\n" \ + "Lastest available version is unknown.", + current); + + else + { + if (current >= available) + asprintf(&msg, + "Your version is: <b>%d</b>\n\n" \ + "Lastest version is: <b>%d</b>\n\n" \ + "Your software is <span color='green'><b>up-to-date</b></span>.", + current, available); + + else + asprintf(&msg, + "Your version is: <b>%d</b>\n\n" \ + "Lastest version is: <b>%d</b>\n\n" \ + "Your software is <span color='red'><b>outdated</b></span>.", + current, available); + + } + + } + + gtk_label_set_markup(label, msg); + + free(msg); + +} + + +/****************************************************************************** +* * +* Paramètres : button = bouton de défilement des astuces activé; * +* panel = panneau associé comportant des informations utiles. * +* * +* Description : Affiche l'astuce précédente dans la liste globale. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_tip_previous_clicked(GtkButton *button, GWelcomePanel *panel) +{ + if (panel->current > 0) + panel->current--; + else + panel->current = panel->count - 1; + + g_welcome_panel_refresh_tip(panel); + +} + + +/****************************************************************************** +* * +* Paramètres : button = bouton de défilement des astuces activé; * +* panel = panneau associé comportant des informations utiles. * +* * +* Description : Affiche l'astuce suivante dans la liste globale. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_tip_next_clicked(GtkButton *button, GWelcomePanel *panel) +{ + if ((panel->current + 1) < panel->count) + panel->current++; + else + panel->current = 0; + + g_welcome_panel_refresh_tip(panel); + +} + + +/****************************************************************************** +* * +* Paramètres : panel = panneau associé comportant des informations utiles. * +* * +* Description : Actualise l'affichage des astuces. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_welcome_panel_refresh_tip(GWelcomePanel *panel) +{ + GtkLabel *label; /* Etiquette de présentation */ + + assert(panel->current < panel->count); + + label = GTK_LABEL(gtk_builder_get_object(panel->builder, "tip")); + + gtk_label_set_markup(label, panel->tips[panel->current]); + +} + + +/****************************************************************************** +* * +* Paramètres : panel = panneau associé comportant des informations utiles. * +* * +* Description : Indique l'origine de l'affichage du panneau d'accueil. * +* * +* Retour : true si l'affichage est le fait de l'utilisateur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_welcome_panel_get_user_origin(const GWelcomePanel *panel) +{ + return panel->uorigin; + +} + + +/****************************************************************************** +* * +* Paramètres : panel = panneau associé comportant des informations utiles.* +* uorigin = true si l'affichage est le fait de l'utilisateur. * +* * +* Description : Détermine l'origine de l'affichage du panneau d'accueil. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_welcome_panel_set_user_origin(GWelcomePanel *panel, bool uorigin) +{ + panel->uorigin = uorigin; + +} diff --git a/src/gui/panels/welcome.h b/src/gui/panels/welcome.h new file mode 100644 index 0000000..c75d6f5 --- /dev/null +++ b/src/gui/panels/welcome.h @@ -0,0 +1,68 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * welcome.h - prototypes pour le panneau d'accueil par défaut + * + * Copyright (C) 2016 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _GUI_PANELS_WELCOME_H +#define _GUI_PANELS_WELCOME_H + + +#include <i18n.h> + + +#include "panel.h" + + + +#define PANEL_WELCOME_ID _("Welcome") + + +#define G_TYPE_WELCOME_PANEL g_welcome_panel_get_type() +#define G_WELCOME_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_welcome_panel_get_type(), GWelcomePanel)) +#define G_IS_WELCOME_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_welcome_panel_get_type())) +#define G_WELCOME_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WELCOME_PANEL, GWelcomePanelClass)) +#define G_IS_WELCOME_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WELCOME_PANEL)) +#define G_WELCOME_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WELCOME_PANEL, GWelcomePanelClass)) + + +/* Panneau d'accueil par défaut (instance) */ +typedef struct _GWelcomePanel GWelcomePanel; + +/* Panneau d'accueil par défaut (classe) */ +typedef struct _GWelcomePanelClass GWelcomePanelClass; + + +/* Indique le type défini pour un panneau d'accueil. */ +GType g_welcome_panel_get_type(void); + +/* Crée un panneau d'accueil par défaut. */ +GPanelItem *g_welcome_panel_new(void); + +/* Indique l'origine de l'affichage du panneau d'accueil. */ +bool g_welcome_panel_get_user_origin(const GWelcomePanel *); + +/* Détermine l'origine de l'affichage du panneau d'accueil. */ +void g_welcome_panel_set_user_origin(GWelcomePanel *, bool); + + + +#endif /* _GUI_PANELS_WELCOME_H */ diff --git a/src/gui/panels/welcome.ui b/src/gui/panels/welcome.ui new file mode 100644 index 0000000..d016907 --- /dev/null +++ b/src/gui/panels/welcome.ui @@ -0,0 +1,245 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.18.3 --> +<interface> + <requires lib="gtk+" version="3.12"/> + <object class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="stock">gtk-new</property> + <property name="icon_size">6</property> + </object> + <object class="GtkListStore" id="store"> + <columns> + <!-- column-name valid --> + <column type="gboolean"/> + <!-- column-name fullpath --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkOffscreenWindow" id="offscreenwindow1"> + <property name="can_focus">False</property> + <child> + <object class="GtkBox" id="box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="homogeneous">True</property> + <child> + <object class="GtkBox" id="box2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_left">8</property> + <property name="margin_right">8</property> + <property name="margin_top">8</property> + <property name="margin_bottom">8</property> + <property name="orientation">vertical</property> + <property name="spacing">8</property> + <child> + <object class="GtkAlignment" id="alignment1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">center</property> + <property name="top_padding">180</property> + <property name="bottom_padding">30</property> + <child> + <object class="GtkButton" id="button1"> + <property name="label" translatable="yes">New binary...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="image">image1</property> + <property name="image_position">top</property> + <property name="always_show_image">True</property> + <signal name="clicked" handler="on_new_binary_clicked" swapped="no"/> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Last projects:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkTreeView" id="treeview"> + <property name="height_request">250</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="margin_left">8</property> + <property name="hexpand">True</property> + <property name="model">store</property> + <property name="headers_visible">False</property> + <property name="rules_hint">True</property> + <signal name="row-activated" handler="on_row_activated_for_projects" swapped="no"/> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="treeview-selection1"/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="startup"> + <property name="label" translatable="yes">Show this panel at startup.</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="halign">start</property> + <property name="valign">end</property> + <property name="vexpand">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_startup_toggled" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_left">8</property> + <property name="margin_right">8</property> + <property name="margin_top">8</property> + <property name="margin_bottom">8</property> + <property name="orientation">vertical</property> + <property name="spacing">8</property> + <child> + <object class="GtkBox" id="box4"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="homogeneous">True</property> + <child> + <object class="GtkLabel" id="version"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="opacity">0.81999999977648264</property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="opacity">0.81999999999999995</property> + <property name="label" translatable="yes">Get access to the online documentation and stay tuned by visiting the official website : <a href="http://chrysalide.re">chrysalide.re</a> + +You can also follow Chrysalide on Twitter : <a href="http://twitter.com/chrysalide_ref">@chrysalide_ref</a></property> + <property name="use_markup">True</property> + <property name="wrap">True</property> + <property name="track_visited_links">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="tip"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="yalign">1</property> + <property name="xpad">8</property> + <property name="ypad">8</property> + <property name="label" translatable="yes">label</property> + <property name="wrap">True</property> + <property name="selectable">True</property> + <signal name="draw" handler="on_tip_background_draw" swapped="no"/> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButtonBox" id="buttonbox1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">8</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="button3"> + <property name="label" translatable="yes">Previous</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="clicked" handler="on_tip_previous_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="button2"> + <property name="label" translatable="yes">Next</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="clicked" handler="on_tip_next_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> +</interface> |