From 93dfdc30d815629a7e0c9393f0e8f0462844ff56 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Thu, 24 Dec 2020 17:26:51 +0100 Subject: Ported the panel update mechanisms to the Python API. --- configure.ac | 1 + plugins/pychrysalide/gui/Makefile.am | 5 +- plugins/pychrysalide/gui/module.c | 4 +- plugins/pychrysalide/gui/panel.c | 90 ++++ plugins/pychrysalide/gui/panels/Makefile.am | 19 + plugins/pychrysalide/gui/panels/module.c | 101 ++++ plugins/pychrysalide/gui/panels/module.h | 42 ++ plugins/pychrysalide/gui/panels/updating.c | 734 ++++++++++++++++++++++++++++ plugins/pychrysalide/gui/panels/updating.h | 45 ++ plugins/pychrysalide/helpers.c | 46 ++ src/gui/panels/bintree.c | 23 +- src/gui/panels/errors.c | 15 +- src/gui/panels/strings.c | 19 +- src/gui/panels/symbols.c | 19 +- src/gui/panels/symbols.ui | 93 ++-- src/gui/panels/updating-int.h | 4 +- src/gui/panels/updating.c | 56 ++- src/gui/panels/updating.h | 4 +- 18 files changed, 1217 insertions(+), 103 deletions(-) create mode 100644 plugins/pychrysalide/gui/panels/Makefile.am create mode 100644 plugins/pychrysalide/gui/panels/module.c create mode 100644 plugins/pychrysalide/gui/panels/module.h create mode 100644 plugins/pychrysalide/gui/panels/updating.c create mode 100644 plugins/pychrysalide/gui/panels/updating.h diff --git a/configure.ac b/configure.ac index 3837315..e57fbb6 100644 --- a/configure.ac +++ b/configure.ac @@ -488,6 +488,7 @@ AC_CONFIG_FILES([Makefile plugins/pychrysalide/gtkext/graph/Makefile plugins/pychrysalide/gui/Makefile plugins/pychrysalide/gui/core/Makefile + plugins/pychrysalide/gui/panels/Makefile plugins/pychrysalide/mangling/Makefile plugins/python/Makefile plugins/python/abackup/Makefile diff --git a/plugins/pychrysalide/gui/Makefile.am b/plugins/pychrysalide/gui/Makefile.am index ca6bee5..cd8f05d 100644 --- a/plugins/pychrysalide/gui/Makefile.am +++ b/plugins/pychrysalide/gui/Makefile.am @@ -9,7 +9,8 @@ libpychrysagui_la_SOURCES = \ panel.h panel.c libpychrysagui_la_LIBADD = \ - core/libpychrysaguicore.la + core/libpychrysaguicore.la \ + panels/libpychrysaguipanels.la libpychrysagui_la_LDFLAGS = @@ -24,4 +25,4 @@ AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJE AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) -SUBDIRS = core +SUBDIRS = core panels diff --git a/plugins/pychrysalide/gui/module.c b/plugins/pychrysalide/gui/module.c index 1ff7b1b..365cab6 100644 --- a/plugins/pychrysalide/gui/module.c +++ b/plugins/pychrysalide/gui/module.c @@ -28,11 +28,11 @@ #include - #include "item.h" #include "menubar.h" #include "panel.h" #include "core/module.h" +#include "panels/module.h" #include "../helpers.h" @@ -74,6 +74,7 @@ bool add_gui_module(PyObject *super) result = (module != NULL); if (result) result = add_gui_core_module(module); + if (result) result = add_gui_panels_module(module); if (!result) Py_XDECREF(module); @@ -106,6 +107,7 @@ bool populate_gui_module(void) if (result) result = ensure_python_panel_item_is_registered(); if (result) result = populate_gui_core_module(); + if (result) result = populate_gui_panels_module(); assert(result); diff --git a/plugins/pychrysalide/gui/panel.c b/plugins/pychrysalide/gui/panel.c index 160a7a3..2afb2a1 100644 --- a/plugins/pychrysalide/gui/panel.c +++ b/plugins/pychrysalide/gui/panel.c @@ -82,6 +82,12 @@ static PyObject *py_panel_item_dock(PyObject *, PyObject *); /* Supprime un panneau de l'ensemble affiché. */ static PyObject *py_panel_item_undock(PyObject *, PyObject *); +/* Bascule l'affichage d'un panneau après sa mise à jour. */ +static PyObject *py_panel_item_switch_to_updated_content(PyObject *, PyObject *); + +/* Bascule l'affichage d'un panneau avant sa mise à jour. */ +static PyObject *py_panel_item_switch_to_updating_mask(PyObject *, PyObject *); + /* Fournit une indication sur la personnalité du panneau. */ static PyObject *py_panel_item_get_personality(PyObject *, void *); @@ -670,6 +676,88 @@ static PyObject *py_panel_item_undock(PyObject *self, PyObject *args) /****************************************************************************** * * +* Paramètres : self = panneau ciblé par une mise à jour. * +* args = arguments fournis à l'appel. * +* * +* Description : Bascule l'affichage d'un panneau avant sa mise à jour. * +* * +* Retour : Py_None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_panel_item_switch_to_updating_mask(PyObject *self, PyObject *args) +{ + GPanelItem *item; /* Panneau à manipuler */ + +#define PANEL_ITEM_SWITCH_TO_UPDATING_MASK_METHOD PYTHON_METHOD_DEF \ +( \ + switch_to_updating_mask, "$self, /", \ + METH_NOARGS, py_panel_item, \ + "Switch the panel content display before its update." \ + "\n" \ + "The *Gtk.Builder* helper linked to the panel has to define the" \ + " following widgets:\n" \ + "* 'stack': a *Gtk.Stack* instance containing the other widget;\n" \ + "* 'content': the main *Gtk.Widget* used to show the main panel" \ + " content;\n" \ + "* 'mask': a widget displayed during computing, like a" \ + " *Gtk.Spinner* instance." \ +) + + item = G_PANEL_ITEM(pygobject_get(self)); + + g_panel_item_switch_to_updating_mask(item); + + Py_RETURN_NONE; + +} + + +/****************************************************************************** +* * +* Paramètres : self = panneau ciblé par une mise à jour. * +* args = arguments fournis à l'appel. * +* * +* Description : Bascule l'affichage d'un panneau après sa mise à jour. * +* * +* Retour : Py_None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_panel_item_switch_to_updated_content(PyObject *self, PyObject *args) +{ + GPanelItem *item; /* Panneau à manipuler */ + +#define PANEL_ITEM_SWITCH_TO_UPDATED_CONTENT_METHOD PYTHON_METHOD_DEF \ +( \ + switch_to_updated_content, "$self, /", \ + METH_NOARGS, py_panel_item, \ + "Switch the panel content display after its update." \ + "\n" \ + "The *Gtk.Builder* helper linked to the panel has to define the" \ + " following widgets:\n" \ + "* 'stack': a *Gtk.Stack* instance containing the other widget;\n" \ + "* 'content': the main *Gtk.Widget* used to show the main panel" \ + " content;\n" \ + "* 'mask': a widget displayed during computing, like a" \ + " *Gtk.Spinner* instance." \ +) + + item = G_PANEL_ITEM(pygobject_get(self)); + + g_panel_item_switch_to_updated_content(item); + + Py_RETURN_NONE; + +} + + +/****************************************************************************** +* * * Paramètres : self = objet Python concerné par l'appel. * * closure = non utilisé ici. * * * @@ -1023,6 +1111,8 @@ PyTypeObject *get_python_panel_item_type(void) static PyMethodDef py_panel_item_methods[] = { PANEL_ITEM_DOCK_METHOD, PANEL_ITEM_UNDOCK_METHOD, + PANEL_ITEM_SWITCH_TO_UPDATING_MASK_METHOD, + PANEL_ITEM_SWITCH_TO_UPDATED_CONTENT_METHOD, { NULL } }; diff --git a/plugins/pychrysalide/gui/panels/Makefile.am b/plugins/pychrysalide/gui/panels/Makefile.am new file mode 100644 index 0000000..a6e3635 --- /dev/null +++ b/plugins/pychrysalide/gui/panels/Makefile.am @@ -0,0 +1,19 @@ + +noinst_LTLIBRARIES = libpychrysaguipanels.la + +libpychrysaguipanels_la_SOURCES = \ + module.h module.c \ + updating.h updating.c + +libpychrysaguipanels_la_LDFLAGS = + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libpychrysaguipanels_la_SOURCES:%c=) + + +AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src + +AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/gui/panels/module.c b/plugins/pychrysalide/gui/panels/module.c new file mode 100644 index 0000000..f904188 --- /dev/null +++ b/plugins/pychrysalide/gui/panels/module.c @@ -0,0 +1,101 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire panels en tant que module + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 "module.h" + + +#include + + +#include "updating.h" +#include "../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'gui.panels' à un module Python. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_gui_panels_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_GUI_PANELS_DOC \ + "This module defines all the core panels and their helper class" \ + " pychrysalide.gui.panels.UpdatablePanel as well." + + static PyModuleDef py_chrysalide_gui_panels_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.gui.panels", + .m_doc = PYCHRYSALIDE_GUI_PANELS_DOC, + + .m_size = -1, + + }; + + module = build_python_module(super, &py_chrysalide_gui_panels_module); + + result = (module != NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'gui.panels'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_gui_panels_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_updatable_panel_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/gui/panels/module.h b/plugins/pychrysalide/gui/panels/module.h new file mode 100644 index 0000000..e926107 --- /dev/null +++ b/plugins/pychrysalide/gui/panels/module.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire panels en tant que module + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 _PLUGINS_PYCHRYSALIDE_GUI_PANELS_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_GUI_PANELS_MODULE_H + + +#include +#include + + + +/* Ajoute le module 'gui.panels' à un module Python. */ +bool add_gui_panels_module(PyObject *); + +/* Intègre les objets du module 'gui.panels'. */ +bool populate_gui_panels_module(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_GUI_PANELS_MODULE_H */ diff --git a/plugins/pychrysalide/gui/panels/updating.c b/plugins/pychrysalide/gui/panels/updating.c new file mode 100644 index 0000000..5898575 --- /dev/null +++ b/plugins/pychrysalide/gui/panels/updating.c @@ -0,0 +1,734 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * updating.c - équivalent Python du fichier "gui/panels/updating.h" + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 "updating.h" + + +#include + + +#include +#include + + +#include "../../access.h" +#include "../../helpers.h" + + + +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ + + +/* Procède à l'initialisation de l'interface de génération. */ +static void py_updatable_panel_interface_init(GUpdatablePanelIface *, gpointer *); + +/* Prépare une opération de mise à jour de panneau. */ +static bool py_updatable_panel_setup_wrapper(const GUpdatablePanel *, unsigned int, size_t *, void **, char **); + +/* Obtient le groupe de travail dédié à une mise à jour. */ +static wgroup_id_t py_updatable_panel_get_group_wrapper(const GUpdatablePanel *); + +/* Bascule l'affichage d'un panneau avant mise à jour. */ +static void py_updatable_panel_introduce_wrapper(const GUpdatablePanel *, unsigned int, void *); + +/* Réalise une opération de mise à jour de panneau. */ +static void py_updatable_panel_process_wrapper(const GUpdatablePanel *, unsigned int, GtkStatusStack *, activity_id_t, void *); + +/* Bascule l'affichage d'un panneau après mise à jour. */ +static void py_updatable_panel_conclude_wrapper(GUpdatablePanel *, unsigned int, void *); + +/* Supprime les données dynamiques utilisées à la mise à jour. */ +static void py_updatable_panel_clean_data_wrapper(const GUpdatablePanel *, unsigned int, void *); + + + +/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */ + + +/* Prépare et lance l'actualisation d'un panneau. */ +static PyObject *py_updatable_panel_run_update(PyObject *, PyObject *); + + + +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : iface = interface GLib à initialiser. * +* unused = adresse non utilisée ici. * +* * +* Description : Procède à l'initialisation de l'interface de génération. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_updatable_panel_interface_init(GUpdatablePanelIface *iface, gpointer *unused) +{ + +#define UPDATABLE_PANEL_DOC \ + "UpdatablePanel defines an interface as helper for panels updates." \ + " Panels contents can thus get hidden then restored easily once data" \ + " is fully processed.\n" \ + "\n" \ + "A typical class declaration for a new implementation looks like:\n" \ + "\n" \ + " class NewImplem(GObject.Object, UpdatablePanel):\n" \ + " ...\n" \ + "\n" \ + "The following methods have to be defined for new implementations:\n" \ + "* pychrysalide.gui.panels.UpdatablePanel._setup();\n" \ + "* pychrysalide.gui.panels.UpdatablePanel._introduce();\n" \ + "* pychrysalide.gui.panels.UpdatablePanel._process();\n" \ + "* pychrysalide.gui.panels.UpdatablePanel._conclude();\n" \ + "* pychrysalide.gui.panels.UpdatablePanel._clean_data().\n" \ + "\n" \ + "The following attribute has to be defined for new implementations:\n" \ + "* pychrysalide.gui.panels.UpdatablePanel._working_group_id.\n" \ + + iface->setup = py_updatable_panel_setup_wrapper; + iface->get_group = py_updatable_panel_get_group_wrapper; + iface->introduce = py_updatable_panel_introduce_wrapper; + iface->process = py_updatable_panel_process_wrapper; + iface->conclude = py_updatable_panel_conclude_wrapper; + iface->clean = py_updatable_panel_clean_data_wrapper; + +} + + +/****************************************************************************** +* * +* Paramètres : panel = panneau ciblé par une mise à jour. * +* uid = identifiant de la phase de traitement. * +* count = nombre d'étapes à prévoir dans le traitement. [OUT] * +* data = données sur lesquelles s'appuyer ensuite. [OUT] * +* msg = description du message d'information. [OUT] * +* * +* Description : Prépare une opération de mise à jour de panneau. * +* * +* Retour : Bilan de la préparation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_updatable_panel_setup_wrapper(const GUpdatablePanel *panel, unsigned int uid, size_t *count, void **data, char **msg) +{ + bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + PyObject *item; /* Elément obtenu */ + +#define UPDATABLE_PANEL_SETUP_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _setup, "$self, uid, /", \ + METH_VARARGS, \ + "Abstract method used to prepare an update process for a panel.\n" \ + "\n" \ + "The *uid* identifier is an arbitrary number identifying the update" \ + " process.\n" \ + "\n" \ + "The expected result is a tuple containing three items:\n" \ + "* the number of items to be processed, in order to synchronize with" \ + " the progress shown in the status bar;\n" \ + "* an optional object used to store final result (or None);\n" \ + "* a text message to display as the name of the update operation." \ +) + + result = false; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(panel)); + + if (has_python_method(pyobj, "_setup")) + { + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(uid)); + + pyret = run_python_method(pyobj, "_setup", args); + + if (!PyTuple_Check(pyret) || PyTuple_Size(pyret) != 3) + { + PyErr_SetString(PyExc_ValueError, "the provided quantity has to be a tuple with three items"); + goto exit; + } + + item = PyTuple_GetItem(pyret, 0); + if (!PyLong_Check(item)) goto exit; + + *count = PyLong_AsUnsignedLongLong(item); + + item = PyTuple_GetItem(pyret, 1); + + Py_INCREF(item); + *data = item; + + item = PyTuple_GetItem(pyret, 2); + if (!PyUnicode_Check(item)) + { + Py_DECREF(item); + *data = NULL; + goto exit; + } + + *msg = strdup(PyUnicode_AsUTF8(item)); + + result = true; + + exit: + + Py_XDECREF(pyret); + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : panel = panneau ciblé par une mise à jour. * +* * +* Description : Obtient le groupe de travail dédié à une mise à jour. * +* * +* Retour : Identifiant de groupe de travail. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static wgroup_id_t py_updatable_panel_get_group_wrapper(const GUpdatablePanel *panel) +{ + wgroup_id_t result; /* Identifiant à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyattr; /* Attribut de l'objet Python */ + int ret; /* Bilan d'une conversion */ + +#define UPDATABLE_PANEL_WORKING_GROUP_ID_ATTRIB_WRAPPER PYTHON_GETTER_WRAPPER_DEF \ +( \ + _working_group_id, \ + "Identifier of a dedicated working group processing panel update jobs.\n" \ + "\n" \ + "The result has to be an integer." \ +) + + result = DEFAULT_WORK_GROUP; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(panel)); + + if (PyObject_HasAttrString(pyobj, "_working_group_id")) + { + pyattr = PyObject_GetAttrString(pyobj, "_working_group_id"); + + if (pyattr != NULL) + { + ret = PyLong_Check(pyattr); + + if (ret) + result = PyLong_AsUnsignedLongLong(pyattr); + + Py_DECREF(pyattr); + + } + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : panel = panneau ciblé par une mise à jour. * +* uid = identifiant de la phase de traitement. * +* data = données préparées par l'appelant. * +* * +* Description : Bascule l'affichage d'un panneau avant mise à jour. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_updatable_panel_introduce_wrapper(const GUpdatablePanel *panel, unsigned int uid, void *data) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pydata; /* Données au format Python */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + +#define UPDATABLE_PANEL_INTRODUCE_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _introduce, "$self, uid, data, /", \ + METH_VARARGS, \ + "Abstract method used to introduce the update process; display switch" \ + " is here an option.\n" \ + "\n" \ + "The *uid* identifier is the same identifier provided for a previous" \ + " call to pychrysalide.gui.panels.UpdatablePanel._setup(), and *data*" \ + " is an optional object instance." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(panel)); + pydata = (PyObject *)data; + + if (has_python_method(pyobj, "_introduce")) + { + Py_INCREF(pydata); + + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(uid)); + PyTuple_SetItem(args, 1, pydata); + + pyret = run_python_method(pyobj, "_introduce", args); + + Py_XDECREF(pyret); + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + +} + + +/****************************************************************************** +* * +* Paramètres : panel = panneau ciblé par une mise à jour. * +* uid = identifiant de la phase de traitement. * +* status = barre de statut à tenir informée. * +* id = identifiant pour le suivi de la progression. * +* data = données préparées par l'appelant. * +* * +* Description : Réalise une opération de mise à jour de panneau. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_updatable_panel_process_wrapper(const GUpdatablePanel *panel, unsigned int uid, GtkStatusStack *status, activity_id_t id, void *data) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pydata; /* Données au format Python */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + +#define UPDATABLE_PANEL_PROCESS_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _process, "$self, uid, status, id, data, /", \ + METH_VARARGS, \ + "Abstract method used to perform the computing of data to render.\n" \ + "\n" \ + "The *uid* identifier is the same identifier provided for a previous" \ + " call to pychrysalide.gui.panels.UpdatablePanel._setup(), *status* is" \ + " a pychrysalide.gtkext.StatusStack instance, *id* refers to the" \ + " identifier for message display inside the status bar and *data* is" \ + " an optional object instance.\n" \ + "\n" \ + "The method is called from a dedicated processing thread." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(panel)); + pydata = (PyObject *)data; + + if (has_python_method(pyobj, "_process")) + { + Py_INCREF(pydata); + + args = PyTuple_New(4); + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(uid)); + PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(status))); + PyTuple_SetItem(args, 2, PyLong_FromUnsignedLong(id)); + PyTuple_SetItem(args, 3, pydata); + + pyret = run_python_method(pyobj, "_process", args); + + Py_XDECREF(pyret); + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + +} + + +/****************************************************************************** +* * +* Paramètres : panel = panneau ciblé par une mise à jour. * +* uid = identifiant de la phase de traitement. * +* data = données préparées par l'appelant. * +* * +* Description : Bascule l'affichage d'un panneau après mise à jour. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_updatable_panel_conclude_wrapper(GUpdatablePanel *panel, unsigned int uid, void *data) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pydata; /* Données au format Python */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + +#define UPDATABLE_PANEL_CONCLUDE_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _conclude, "$self, uid, data, /", \ + METH_VARARGS, \ + "Abstract method used to conclude the update process and to display" \ + " the computed data.\n" \ + "\n" \ + "The *uid* identifier is the same identifier provided for a previous" \ + " call to pychrysalide.gui.panels.UpdatablePanel._setup(), and *data*" \ + " is an optional object instance." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(panel)); + pydata = (PyObject *)data; + + if (has_python_method(pyobj, "_conclude")) + { + Py_INCREF(pydata); + + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(uid)); + PyTuple_SetItem(args, 1, pydata); + + pyret = run_python_method(pyobj, "_conclude", args); + + Py_XDECREF(pyret); + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + +} + + +/****************************************************************************** +* * +* Paramètres : panel = panneau ciblé par une mise à jour. * +* uid = identifiant de la phase de traitement. * +* data = données en place à nettoyer avant suppression. * +* * +* Description : Supprime les données dynamiques utilisées à la mise à jour. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_updatable_panel_clean_data_wrapper(const GUpdatablePanel *panel, unsigned int uid, void *data) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pydata; /* Données au format Python */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + +#define UPDATABLE_PANEL_CLEAN_DATA_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _clean_data, "$self, uid, data, /", \ + METH_VARARGS, \ + "Abstract method used to delete dynamically generated objects for the" \ + " panel update.\n" \ + "\n" \ + "The *uid* identifier is the same identifier provided for a previous" \ + " call to pychrysalide.gui.panels.UpdatablePanel._setup(), and *data*" \ + " is an optional object instance.\n" \ + "\n" \ + "As the user *data* reference counter is decreased automatically after" \ + " this wrapper is called (if existing), there should be no need to" \ + " define such a wrapper, except if the panel needs some kind of" \ + " notification at the end of the update or if it still owns a reference"\ + " to this *data*." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(panel)); + pydata = (PyObject *)data; + + if (has_python_method(pyobj, "_clean_data")) + { + Py_INCREF(pydata); + + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(uid)); + PyTuple_SetItem(args, 1, pydata); + + pyret = run_python_method(pyobj, "_clean_data", args); + + Py_XDECREF(pyret); + + Py_DECREF(args); + + } + + Py_DECREF(pydata); + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* CONNEXION AVEC L'API DE PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : self = NULL car méthode statique. * +* args = paramètres à transmettre à l'appel natif. * +* * +* Description : Prépare et lance l'actualisation d'un panneau. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_updatable_panel_run_update(PyObject *self, PyObject *args) +{ + PyObject *result; /* Désignation à retourner */ + unsigned int uid; /* Identifiant de mise à jour */ + int ret; /* Bilan de lecture des args. */ + GUpdatablePanel *panel; /* Instance à manipuler */ + +#define UPDATABLE_PANEL_RUN_UPDATE_METHOD PYTHON_METHOD_DEF \ +( \ + run_update, "self, uid, /", \ + METH_VARARGS, py_updatable_panel, \ + "Prepare and run an update for the panel.\n" \ + "\n" \ + "The *uid* argument is an arbitrary integer provided" \ + " as internal identifier for the caller." \ +) + + ret = PyArg_ParseTuple(args, "I", &uid); + if (!ret) return NULL; + + panel = G_UPDATABLE_PANEL(pygobject_get(self)); + + run_panel_update(panel, uid); + + result = Py_None; + Py_INCREF(result); + + return result; + + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_updatable_panel_type(void) +{ + static PyMethodDef py_updatable_panel_methods[] = { + UPDATABLE_PANEL_SETUP_WRAPPER, + UPDATABLE_PANEL_INTRODUCE_WRAPPER, + UPDATABLE_PANEL_PROCESS_WRAPPER, + UPDATABLE_PANEL_CONCLUDE_WRAPPER, + UPDATABLE_PANEL_CLEAN_DATA_WRAPPER, + UPDATABLE_PANEL_RUN_UPDATE_METHOD, + { NULL } + }; + + static PyGetSetDef py_updatable_panel_getseters[] = { + UPDATABLE_PANEL_WORKING_GROUP_ID_ATTRIB_WRAPPER, + { NULL } + }; + + static PyTypeObject py_updatable_panel_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.gui.panels.UpdatablePanel", + .tp_basicsize = sizeof(PyObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = UPDATABLE_PANEL_DOC, + + .tp_methods = py_updatable_panel_methods, + .tp_getset = py_updatable_panel_getseters, + + }; + + return &py_updatable_panel_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.gui....UpdatablePanel'.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_updatable_panel_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'LineGenerator' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + static GInterfaceInfo info = { /* Paramètres d'inscription */ + + .interface_init = (GInterfaceInitFunc)py_updatable_panel_interface_init, + .interface_finalize = NULL, + .interface_data = NULL, + + }; + + type = get_python_updatable_panel_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.gui.panels"); + + dict = PyModule_GetDict(module); + + if (!register_interface_for_pygobject(dict, G_TYPE_UPDATABLE_PANEL, type, &info)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en mécanisme de mise à jour de panneau. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_updatable_panel(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_updatable_panel_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to updatable panel"); + break; + + case 1: + *((GUpdatablePanel **)dst) = G_UPDATABLE_PANEL(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/gui/panels/updating.h b/plugins/pychrysalide/gui/panels/updating.h new file mode 100644 index 0000000..a9e5799 --- /dev/null +++ b/plugins/pychrysalide/gui/panels/updating.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * updating.h - prototypes pour l'équivalent Python du fichier "gui/panels/updating.h" + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 _PLUGINS_PYCHRYSALIDE_GUI_PANELS_UPDATING_H +#define _PLUGINS_PYCHRYSALIDE_GUI_PANELS_UPDATING_H + + +#include +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_updatable_panel_type(void); + +/* Prend en charge l'objet 'pychrysalide.gui.panels.UpdatablePanel'. */ +bool ensure_python_updatable_panel_is_registered(void); + +/* Tente de convertir en générateur de lignes. */ +int convert_to_updatable_panel(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_GUI_PANELS_UPDATING_H */ diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c index f811ad3..b2ecbec 100644 --- a/plugins/pychrysalide/helpers.c +++ b/plugins/pychrysalide/helpers.c @@ -977,6 +977,11 @@ bool register_class_for_dynamic_pygobject(GType gtype, PyTypeObject *type, PyTyp PyObject *modname; /* Nom du module du type */ PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire dudit module */ + Py_ssize_t i; /* Boucle de parcours */ + PyObject *mro_base; /* Base finale effective */ + GType itype; /* Type d'interface implémentée*/ + GQuark pyginterface_info_key; /* Clef d'accès non déclarée */ + const GInterfaceInfo *iinfo; /* Informations associées */ /** * Lors de l'appel à pygobject_register_class(), PyGObject remplace systématiquement @@ -1023,6 +1028,47 @@ bool register_class_for_dynamic_pygobject(GType gtype, PyTypeObject *type, PyTyp Py_TYPE(type) = legacy_parent; + /** + * Comme la mise en place dynamique de nouveau GType court-circuite les + * mécanismes internes de pygobject, les interfaces implémentées ne sont + * nominalement plus complétées. + * + * On reprend donc la logique copiée depuis le contenu de la fonction + * pyg_type_add_interfaces() du fichier "pygobject-3.22.0/gi/gobjectmodule.c". + */ + + for (i = 0; i < PyTuple_GET_SIZE(type->tp_mro); i++) + { + mro_base = PyTuple_GET_ITEM(type->tp_mro, i); + + if (!PyType_Check(mro_base)) + continue; + + itype = pyg_type_from_object(mro_base); + + if (itype == G_TYPE_INTERFACE) + continue; + + if (!G_TYPE_IS_INTERFACE(itype)) + continue; + + if (!g_type_is_a(gtype, itype)) + { + /** + * Reproduction de pyg_lookup_interface_info(). + */ + + pyginterface_info_key = g_quark_from_static_string("PyGInterface::info"); + + iinfo = g_type_get_qdata(itype, pyginterface_info_key); + assert(iinfo != NULL); + + g_type_add_interface_static(gtype, itype, iinfo); + + } + + } + return result; } diff --git a/src/gui/panels/bintree.c b/src/gui/panels/bintree.c index db5e774..c31bd88 100644 --- a/src/gui/panels/bintree.c +++ b/src/gui/panels/bintree.c @@ -190,7 +190,7 @@ struct _bintree_update_data static bool is_bintree_column_matching(const bintree_update_data *, GBinPortion *, gint, regmatch_t *); /* Prépare une opération de mise à jour de panneau. */ -static const char *g_bintree_panel_setup(const GBintreePanel *, unsigned int, size_t *, bintree_update_data **); +static bool g_bintree_panel_setup(const GBintreePanel *, unsigned int, size_t *, bintree_update_data **, char **); /* Bascule l'affichage d'un panneau avant mise à jour. */ static void g_bintree_panel_introduce(const GBintreePanel *, unsigned int, bintree_update_data *); @@ -202,7 +202,7 @@ static void g_bintree_panel_process(const GBintreePanel *, unsigned int, GtkStat static void g_bintree_panel_conclude(GBintreePanel *, unsigned int, bintree_update_data *); /* Supprime les données dynamiques utilisées à la mise à jour. */ -static void g_bintree_panel_clean_data(GUpdatablePanel *, unsigned int, bintree_update_data *); +static void g_bintree_panel_clean_data(const GUpdatablePanel *, unsigned int, bintree_update_data *); @@ -1132,24 +1132,27 @@ static bool is_bintree_column_matching(const bintree_update_data *data, GBinPort * uid = identifiant de la phase de traitement. * * count = nombre d'étapes à prévoir dans le traitement. [OUT] * * data = données sur lesquelles s'appuyer ensuite. [OUT] * +* msg = description du message d'information. [OUT] * * * * Description : Prépare une opération de mise à jour de panneau. * * * -* Retour : Description du message d'information. * +* Retour : Bilan de la préparation. * * * * Remarques : - * * * ******************************************************************************/ -static const char *g_bintree_panel_setup(const GBintreePanel *panel, unsigned int uid, size_t *count, bintree_update_data **data) +static bool g_bintree_panel_setup(const GBintreePanel *panel, unsigned int uid, size_t *count, bintree_update_data **data, char **msg) { - const char *result; /* Message à retourner */ + bool result; /* Bilan à retourner */ #ifndef NDEBUG int ret; /* Bilan de mise en place */ #endif GtkBuilder *builder; /* Constructeur utilisé */ GtkTreeView *treeview; /* Arborescence graphique */ + result = true; + *data = malloc(sizeof(bintree_update_data)); switch (uid) @@ -1159,7 +1162,7 @@ static const char *g_bintree_panel_setup(const GBintreePanel *panel, unsigned in *count = 0; (*data)->count = 0; - result = _("Loading portions contained in the binary format..."); + *msg = strdup(_("Loading portions contained in the binary format...")); break; @@ -1168,20 +1171,20 @@ static const char *g_bintree_panel_setup(const GBintreePanel *panel, unsigned in *count = panel->count; (*data)->count = panel->count; - result = _("Filtering portions contained in the binary format..."); + *msg = strdup(_("Filtering portions contained in the binary format...")); break; default: /* Pour GCC... */ assert(false); - result = ""; + result = false; break; } if (G_PANEL_ITEM(panel)->filter != NULL) { - (*data)->filter = (regex_t *)malloc(sizeof(regex_t)); + (*data)->filter = malloc(sizeof(regex_t)); #ifndef NDEBUG ret = regcomp((*data)->filter, G_PANEL_ITEM(panel)->filter, REG_EXTENDED | REG_ICASE); @@ -1375,7 +1378,7 @@ static void g_bintree_panel_conclude(GBintreePanel *panel, unsigned int uid, bin * * ******************************************************************************/ -static void g_bintree_panel_clean_data(GUpdatablePanel *panel, unsigned int uid, bintree_update_data *data) +static void g_bintree_panel_clean_data(const GUpdatablePanel *panel, unsigned int uid, bintree_update_data *data) { size_t i; /* Boucle de parcours */ diff --git a/src/gui/panels/errors.c b/src/gui/panels/errors.c index d567511..2b5353f 100644 --- a/src/gui/panels/errors.c +++ b/src/gui/panels/errors.c @@ -178,7 +178,7 @@ struct _error_update_data /* Prépare une opération de mise à jour de panneau. */ -static const char *g_error_panel_setup(const GErrorPanel *, unsigned int, size_t *, error_update_data **); +static bool g_error_panel_setup(const GErrorPanel *, unsigned int, size_t *, error_update_data **, char **); /* Bascule l'affichage d'un panneau avant mise à jour. */ static void g_error_panel_introduce(const GErrorPanel *, unsigned int, error_update_data *); @@ -1046,6 +1046,7 @@ static void on_error_selection_changed(GtkTreeSelection *selection, gpointer unu * uid = identifiant de la phase de traitement. * * count = nombre d'étapes à prévoir dans le traitement. [OUT] * * data = données sur lesquelles s'appuyer ensuite. [OUT] * +* msg = description du message d'information. [OUT] * * * * Description : Prépare une opération de mise à jour de panneau. * * * @@ -1055,14 +1056,16 @@ static void on_error_selection_changed(GtkTreeSelection *selection, gpointer unu * * ******************************************************************************/ -static const char *g_error_panel_setup(const GErrorPanel *panel, unsigned int uid, size_t *count, error_update_data **data) +static bool g_error_panel_setup(const GErrorPanel *panel, unsigned int uid, size_t *count, error_update_data **data, char **msg) { - const char *result; /* Message à retourner */ + bool result; /* Bilan à retourner */ GBinFormat *format; /* Format du binaire */ size_t fcount; /* Quantité d'erreurs #1 */ GArchProcessor *proc; /* Architecture du binaire */ size_t pcount; /* Quantité d'erreurs #2 */ + result = true; + *data = malloc(sizeof(error_update_data)); switch (uid) @@ -1087,7 +1090,7 @@ static const char *g_error_panel_setup(const GErrorPanel *panel, unsigned int ui *count = fcount + pcount; - result = _("Loading errors occurred during the disassembling process..."); + *msg = strdup(_("Loading errors occurred during the disassembling process...")); (*data)->count = *count; (*data)->kept = 0; @@ -1098,7 +1101,7 @@ static const char *g_error_panel_setup(const GErrorPanel *panel, unsigned int ui *count = panel->count; - result = _("Filtering errors occurred during the disassembling process..."); + *msg = strdup(_("Filtering errors occurred during the disassembling process...")); (*data)->count = panel->count; (*data)->kept = 0; @@ -1107,7 +1110,7 @@ static const char *g_error_panel_setup(const GErrorPanel *panel, unsigned int ui default: /* Pour GCC... */ assert(false); - result = ""; + result = false; break; } diff --git a/src/gui/panels/strings.c b/src/gui/panels/strings.c index 33b715b..f9d6b00 100644 --- a/src/gui/panels/strings.c +++ b/src/gui/panels/strings.c @@ -211,7 +211,7 @@ static bool is_string_name_matching(const strings_update_data *, GtkTreeModel *, static bool is_string_value_matching(const strings_update_data *, GtkTreeModel *, GtkTreeIter *, regmatch_t *); /* Prépare une opération de mise à jour de panneau. */ -static const char *g_strings_panel_setup(const GStringsPanel *, unsigned int, size_t *, strings_update_data **); +static bool g_strings_panel_setup(const GStringsPanel *, unsigned int, size_t *, strings_update_data **, char **); /* Bascule l'affichage d'un panneau avant mise à jour. */ static void g_strings_panel_introduce(const GStringsPanel *, unsigned int, strings_update_data *); @@ -223,7 +223,7 @@ static void g_strings_panel_process(const GStringsPanel *, unsigned int, GtkStat static void g_strings_panel_conclude(GStringsPanel *, unsigned int, strings_update_data *); /* Supprime les données dynamiques utilisées à la mise à jour. */ -static void g_strings_panel_clean_data(GUpdatablePanel *, unsigned int, strings_update_data *); +static void g_strings_panel_clean_data(const GUpdatablePanel *, unsigned int, strings_update_data *); @@ -1526,6 +1526,7 @@ static bool is_string_value_matching(const strings_update_data *data, GtkTreeMod * uid = identifiant de la phase de traitement. * * count = nombre d'étapes à prévoir dans le traitement. [OUT] * * data = données sur lesquelles s'appuyer ensuite. [OUT] * +* msg = description du message d'information. [OUT] * * * * Description : Prépare une opération de mise à jour de panneau. * * * @@ -1535,14 +1536,16 @@ static bool is_string_value_matching(const strings_update_data *data, GtkTreeMod * * ******************************************************************************/ -static const char *g_strings_panel_setup(const GStringsPanel *panel, unsigned int uid, size_t *count, strings_update_data **data) +static bool g_strings_panel_setup(const GStringsPanel *panel, unsigned int uid, size_t *count, strings_update_data **data, char **msg) { - const char *result; /* Message à retourner */ + bool result; /* Bilan à retourner */ GBinFormat *format; /* Format du binaire */ #ifndef NDEBUG int ret; /* Bilan de mise en place */ #endif + result = true; + *data = malloc(sizeof(strings_update_data)); switch (uid) @@ -1559,7 +1562,7 @@ static const char *g_strings_panel_setup(const GStringsPanel *panel, unsigned in (*data)->count = 0; - result = _("Loading strings available in the binary format..."); + *msg = strdup(_("Loading strings available in the binary format...")); break; @@ -1568,13 +1571,13 @@ static const char *g_strings_panel_setup(const GStringsPanel *panel, unsigned in *count = panel->count; (*data)->count = panel->count; - result = _("Filtering strings available in the binary format..."); + *msg = strdup(_("Filtering strings available in the binary format...")); break; default: /* Pour GCC... */ assert(false); - result = ""; + result = false; break; } @@ -1735,7 +1738,7 @@ static void g_strings_panel_conclude(GStringsPanel *panel, unsigned int uid, str * * ******************************************************************************/ -static void g_strings_panel_clean_data(GUpdatablePanel *panel, unsigned int uid, strings_update_data *data) +static void g_strings_panel_clean_data(const GUpdatablePanel *panel, unsigned int uid, strings_update_data *data) { if (data->filter != NULL) { diff --git a/src/gui/panels/symbols.c b/src/gui/panels/symbols.c index 152d705..ab7a414 100644 --- a/src/gui/panels/symbols.c +++ b/src/gui/panels/symbols.c @@ -218,7 +218,7 @@ struct _symbols_update_data static bool is_symbol_matching(const symbols_update_data *, const GBinSymbol *, regmatch_t *); /* Prépare une opération de mise à jour de panneau. */ -static const char *g_symbols_panel_setup(const GSymbolsPanel *, unsigned int, size_t *, symbols_update_data **); +static bool g_symbols_panel_setup(const GSymbolsPanel *, unsigned int, size_t *, symbols_update_data **, char **); /* Bascule l'affichage d'un panneau avant mise à jour. */ static void g_symbols_panel_introduce(const GSymbolsPanel *, unsigned int, symbols_update_data *); @@ -230,7 +230,7 @@ static void g_symbols_panel_process(const GSymbolsPanel *, unsigned int, GtkStat static void g_symbols_panel_conclude(GSymbolsPanel *, unsigned int, symbols_update_data *); /* Supprime les données dynamiques utilisées à la mise à jour. */ -static void g_symbols_panel_clean_data(GUpdatablePanel *, unsigned int, symbols_update_data *); +static void g_symbols_panel_clean_data(const GUpdatablePanel *, unsigned int, symbols_update_data *); @@ -1614,6 +1614,7 @@ static bool is_symbol_matching(const symbols_update_data *data, const GBinSymbol * uid = identifiant de la phase de traitement. * * count = nombre d'étapes à prévoir dans le traitement. [OUT] * * data = données sur lesquelles s'appuyer ensuite. [OUT] * +* msg = description du message d'information. [OUT] * * * * Description : Prépare une opération de mise à jour de panneau. * * * @@ -1623,9 +1624,9 @@ static bool is_symbol_matching(const symbols_update_data *data, const GBinSymbol * * ******************************************************************************/ -static const char *g_symbols_panel_setup(const GSymbolsPanel *panel, unsigned int uid, size_t *count, symbols_update_data **data) +static bool g_symbols_panel_setup(const GSymbolsPanel *panel, unsigned int uid, size_t *count, symbols_update_data **data, char **msg) { - const char *result; /* Message à retourner */ + bool result; /* Bilan à retourner */ GBinFormat *format; /* Format du binaire */ #ifndef NDEBUG int ret; /* Bilan de mise en place */ @@ -1633,6 +1634,8 @@ static const char *g_symbols_panel_setup(const GSymbolsPanel *panel, unsigned in GtkBuilder *builder; /* Constructeur utilisé */ GtkTreeView *treeview; /* Arborescence graphique */ + result = true; + *data = malloc(sizeof(symbols_update_data)); switch (uid) @@ -1649,7 +1652,7 @@ static const char *g_symbols_panel_setup(const GSymbolsPanel *panel, unsigned in (*data)->count = 0; - result = _("Loading symbols registered for the binary format..."); + *msg = strdup(_("Loading symbols registered for the binary format...")); break; @@ -1658,13 +1661,13 @@ static const char *g_symbols_panel_setup(const GSymbolsPanel *panel, unsigned in *count = panel->count; (*data)->count = panel->count; - result = _("Filtering symbols registered for the binary format..."); + *msg = strdup(_("Filtering symbols registered for the binary format...")); break; default: /* Pour GCC... */ assert(false); - result = ""; + result = false; break; } @@ -1873,7 +1876,7 @@ static void g_symbols_panel_conclude(GSymbolsPanel *panel, unsigned int uid, sym * * ******************************************************************************/ -static void g_symbols_panel_clean_data(GUpdatablePanel *panel, unsigned int uid, symbols_update_data *data) +static void g_symbols_panel_clean_data(const GUpdatablePanel *panel, unsigned int uid, symbols_update_data *data) { size_t i; /* Boucle de parcours */ diff --git a/src/gui/panels/symbols.ui b/src/gui/panels/symbols.ui index 3c34a29..8e54656 100644 --- a/src/gui/panels/symbols.ui +++ b/src/gui/panels/symbols.ui @@ -1,5 +1,5 @@ - + @@ -28,51 +28,51 @@ store - sorter + sorter True - False + False /org/chrysalide/gui/panels/../../../pixmaps/symbol_class_classic.png True - False + False /org/chrysalide/gui/panels/../../../pixmaps/tbutton_collapse.png True - False + False /org/chrysalide/gui/panels/../../../pixmaps/tbutton_expand.png True - False + False /org/chrysalide/gui/panels/../../../pixmaps/tbutton_list_view.png True - False + False /org/chrysalide/gui/panels/../../../pixmaps/tbutton_tree_view.png - False + False True - False + False vertical True - False + False True - False - Show symbols using a list view - True - tbutton_list_view.png + False + Show symbols using a list view + True + tbutton_list_view.png True tree_display @@ -85,10 +85,10 @@ True - False - Show symbols using a tree view - True - tbutton_tree_view.png + False + Show symbols using a tree view + True + tbutton_tree_view.png @@ -99,7 +99,7 @@ True - False + False False @@ -109,10 +109,10 @@ True - False - Collapse all symbol nodes in the tree view - True - tbutton_collapse.png + False + Collapse all symbol nodes in the tree view + True + tbutton_collapse.png @@ -123,10 +123,10 @@ True - False - Expand all symbol nodes in the tree view - True - tbutton_expand.png + False + Expand all symbol nodes in the tree view + True + tbutton_expand.png @@ -137,10 +137,10 @@ True - False - Show all classes in the tree view - True - symbol_class_classic.png + False + Show all classes in the tree view + True + symbol_class_classic.png @@ -151,7 +151,7 @@ True - False + False False @@ -161,15 +161,15 @@ True - False + False True - True - Filter symbols using POSIX extended regular expressions - edit-find-symbolic - False - False + True + Filter symbols using POSIX extended regular expressions + edit-find-symbolic + False + False @@ -191,20 +191,20 @@ True - False + False True - True - in + True + in treeview True - True + True filter - False - 2 + False + 2 @@ -221,7 +221,7 @@ True - False + False True @@ -239,8 +239,5 @@ - - - diff --git a/src/gui/panels/updating-int.h b/src/gui/panels/updating-int.h index f8d0760..1b742e8 100644 --- a/src/gui/panels/updating-int.h +++ b/src/gui/panels/updating-int.h @@ -30,7 +30,7 @@ /* Prépare une opération de mise à jour de panneau. */ -typedef const char * (* setup_updatable_cb) (const GUpdatablePanel *, unsigned int, size_t *, void **); +typedef bool (* setup_updatable_cb) (const GUpdatablePanel *, unsigned int, size_t *, void **, char **); /* Obtient le groupe de travail dédié à une mise à jour. */ typedef wgroup_id_t (* get_updatable_group_cb) (const GUpdatablePanel *); @@ -45,7 +45,7 @@ typedef void (* process_updatable_cb) (const GUpdatablePanel *, unsigned int, Gt typedef void (* conclude_updatable_cb) (GUpdatablePanel *, unsigned int, void *); /* Supprime les données dynamiques utilisées à la mise à jour. */ -typedef void (* clean_updatable_data_cb) (GUpdatablePanel *, unsigned int, void *); +typedef void (* clean_updatable_data_cb) (const GUpdatablePanel *, unsigned int, void *); /* Mécanisme de mise à jour d'un panneau (interface) */ diff --git a/src/gui/panels/updating.c b/src/gui/panels/updating.c index 31f42c3..c5d59e7 100644 --- a/src/gui/panels/updating.c +++ b/src/gui/panels/updating.c @@ -55,7 +55,7 @@ struct _GPanelUpdate size_t max; /* Marge de progression finale */ void *data; /* Données utiles au traitement*/ - const char *msg; /* Description d'activité */ + char *msg; /* Description d'activité */ }; @@ -120,24 +120,30 @@ static void g_updatable_panel_default_init(GUpdatablePanelInterface *iface) * uid = identifiant de la phase de traitement. * * count = nombre d'étapes à prévoir dans le traitement. [OUT] * * data = données sur lesquelles s'appuyer ensuite. [OUT] * +* msg = description du message d'information. [OUT] * * * * Description : Prépare une opération de mise à jour de panneau. * * * -* Retour : Description du message d'information. * +* Retour : Bilan de la préparation. * * * * Remarques : - * * * ******************************************************************************/ -const char *g_updatable_panel_setup(const GUpdatablePanel *panel, unsigned int uid, size_t *count, void **data) +bool g_updatable_panel_setup(const GUpdatablePanel *panel, unsigned int uid, size_t *count, void **data, char **msg) { + bool result; /* Bilan à retourner */ GUpdatablePanelIface *iface; /* Interface utilisée */ iface = G_UPDATABLE_PANEL_GET_IFACE(panel); + *count = 0; *data = NULL; + *msg = NULL; - return iface->setup(panel, uid, count, data); + result = iface->setup(panel, uid, count, data, msg); + + return result; } @@ -148,7 +154,7 @@ const char *g_updatable_panel_setup(const GUpdatablePanel *panel, unsigned int u * * * Description : Obtient le groupe de travail dédié à une mise à jour. * * * -* Retour : - * +* Retour : Identifiant de groupe de travail. * * * * Remarques : - * * * @@ -259,7 +265,7 @@ void g_updatable_panel_conclude(GUpdatablePanel *panel, unsigned int uid, void * * * ******************************************************************************/ -void g_updatable_panel_clean_data(GUpdatablePanel *panel, unsigned int uid, void *data) +void g_updatable_panel_clean_data(const GUpdatablePanel *panel, unsigned int uid, void *data) { GUpdatablePanelIface *iface; /* Interface utilisée */ @@ -324,6 +330,12 @@ static void g_panel_update_class_init(GPanelUpdateClass *klass) static void g_panel_update_init(GPanelUpdate *update) { + update->panel = NULL; + update->uid = -1; + + update->max = 0; + update->data = NULL; + update->msg = NULL; } @@ -342,7 +354,10 @@ static void g_panel_update_init(GPanelUpdate *update) static void g_panel_update_dispose(GPanelUpdate *update) { - g_object_unref(G_OBJECT(update->panel)); + if (update->panel != NULL) + g_updatable_panel_clean_data(update->panel, update->uid, update->data); + + g_clear_object(&update->panel); G_OBJECT_CLASS(g_panel_update_parent_class)->dispose(G_OBJECT(update)); @@ -363,11 +378,12 @@ static void g_panel_update_dispose(GPanelUpdate *update) static void g_panel_update_finalize(GPanelUpdate *update) { - g_updatable_panel_clean_data(update->panel, update->uid, update->data); - if (update->data != NULL) free(update->data); + if (update->msg != NULL) + free(update->msg); + G_OBJECT_CLASS(g_panel_update_parent_class)->finalize(G_OBJECT(update)); } @@ -389,6 +405,7 @@ static void g_panel_update_finalize(GPanelUpdate *update) GPanelUpdate *g_panel_update_new(GUpdatablePanel *panel, unsigned int uid) { GPanelUpdate *result; /* Tâche à retourner */ + bool status; /* Bilan de la préparation */ result = g_object_new(G_TYPE_PANEL_UPDATE, NULL); @@ -397,7 +414,10 @@ GPanelUpdate *g_panel_update_new(GUpdatablePanel *panel, unsigned int uid) result->uid = uid; - result->msg = g_updatable_panel_setup(panel, uid, &result->max, &result->data); + status = g_updatable_panel_setup(panel, uid, &result->max, &result->data, &result->msg); + + if (!status) + g_clear_object(&result); return result; @@ -477,15 +497,19 @@ void run_panel_update(GUpdatablePanel *panel, unsigned int uid) update = g_panel_update_new(panel, uid); - g_signal_connect_to_main(update, "work-completed", G_CALLBACK(conclude_panel_update), panel, - g_cclosure_marshal_VOID__VOID); + if (update != NULL) + { + g_signal_connect_to_main(update, "work-completed", G_CALLBACK(conclude_panel_update), panel, + g_cclosure_marshal_VOID__VOID); + + g_updatable_panel_introduce(panel, uid, update->data); - g_updatable_panel_introduce(panel, uid, update->data); + queue = get_work_queue(); - queue = get_work_queue(); + gid = g_updatable_panel_get_group(panel); - gid = g_updatable_panel_get_group(panel); + g_work_queue_schedule_work(queue, G_DELAYED_WORK(update), gid); - g_work_queue_schedule_work(queue, G_DELAYED_WORK(update), gid); + } } diff --git a/src/gui/panels/updating.h b/src/gui/panels/updating.h index 8c44795..2293a02 100644 --- a/src/gui/panels/updating.h +++ b/src/gui/panels/updating.h @@ -56,7 +56,7 @@ typedef struct _GUpdatablePanelIface GUpdatablePanelIface; GType g_updatable_panel_get_type(void) G_GNUC_CONST; /* Prépare une opération de mise à jour de panneau. */ -const char *g_updatable_panel_setup(const GUpdatablePanel *, unsigned int, size_t *, void **); +bool g_updatable_panel_setup(const GUpdatablePanel *, unsigned int, size_t *, void **, char **); /* Obtient le groupe de travail dédié à une mise à jour. */ wgroup_id_t g_updatable_panel_get_group(const GUpdatablePanel *); @@ -71,7 +71,7 @@ void g_updatable_panel_process(const GUpdatablePanel *, unsigned int, GtkStatusS void g_updatable_panel_conclude(GUpdatablePanel *, unsigned int, void *); /* Supprime les données dynamiques utilisées à la mise à jour. */ -void g_updatable_panel_clean_data(GUpdatablePanel *, unsigned int, void *); +void g_updatable_panel_clean_data(const GUpdatablePanel *, unsigned int, void *); -- cgit v0.11.2-87-g4458