summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2020-12-24 16:26:51 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2020-12-24 16:26:51 (GMT)
commit93dfdc30d815629a7e0c9393f0e8f0462844ff56 (patch)
tree8fe59f8c0186871ffd79873ec20905bf39170528 /plugins
parentc388ad8910dbb1a3c478176d8b1ab3142fdbd9d5 (diff)
Ported the panel update mechanisms to the Python API.
Diffstat (limited to 'plugins')
-rw-r--r--plugins/pychrysalide/gui/Makefile.am5
-rw-r--r--plugins/pychrysalide/gui/module.c4
-rw-r--r--plugins/pychrysalide/gui/panel.c90
-rw-r--r--plugins/pychrysalide/gui/panels/Makefile.am19
-rw-r--r--plugins/pychrysalide/gui/panels/module.c101
-rw-r--r--plugins/pychrysalide/gui/panels/module.h42
-rw-r--r--plugins/pychrysalide/gui/panels/updating.c734
-rw-r--r--plugins/pychrysalide/gui/panels/updating.h45
-rw-r--r--plugins/pychrysalide/helpers.c46
9 files changed, 1083 insertions, 3 deletions
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 <assert.h>
-
#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 <assert.h>
+
+
+#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 <Python.h>
+#include <stdbool.h>
+
+
+
+/* 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 <pygobject.h>
+
+
+#include <core/queue.h>
+#include <gui/panels/updating-int.h>
+
+
+#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 <Python.h>
+#include <stdbool.h>
+
+
+
+/* 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;
}