From 29ddd755496589e7e1f9e38697e44d3cfe64df5e Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Tue, 1 Sep 2015 21:36:22 +0000
Subject: Added a welcome panel as plugin using Python.

git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@573 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
---
 ChangeLog                              |  39 ++++++++
 configure.ac                           |   1 +
 plugins/pychrysa/pychrysa.c            |  78 ++++++++++++++-
 plugins/python/Makefile.am             |   2 +-
 plugins/python/welcome/Makefile.am     |  14 +++
 plugins/python/welcome/__init__.py     |   4 +
 plugins/python/welcome/binary.py       |  40 ++++++++
 plugins/python/welcome/board.py        | 102 +++++++++++++++++++
 plugins/python/welcome/panel.py        | 147 ++++++++++++++++++++++++++++
 plugins/python/welcome/plugin.py       |  36 +++++++
 plugins/python/welcome/tip.py          | 146 ++++++++++++++++++++++++++++
 plugins/python/welcome/tipoftheday.png | Bin 0 -> 10206 bytes
 plugins/python/welcome/tipoftheday.xcf | Bin 0 -> 17942 bytes
 plugins/python/welcome/version.py      | 107 ++++++++++++++++++++
 plugins/python/welcome/website.py      |  30 ++++++
 src/gui/menus/project.c                |   2 +-
 src/gui/panels/Makefile.am             |   3 +-
 src/gui/panels/panel.c                 |  58 -----------
 src/gui/panels/welcome.c               | 173 ---------------------------------
 src/gui/panels/welcome.h               |  65 -------------
 20 files changed, 743 insertions(+), 304 deletions(-)
 create mode 100644 plugins/python/welcome/Makefile.am
 create mode 100644 plugins/python/welcome/__init__.py
 create mode 100644 plugins/python/welcome/binary.py
 create mode 100644 plugins/python/welcome/board.py
 create mode 100644 plugins/python/welcome/panel.py
 create mode 100644 plugins/python/welcome/plugin.py
 create mode 100644 plugins/python/welcome/tip.py
 create mode 100644 plugins/python/welcome/tipoftheday.png
 create mode 100644 plugins/python/welcome/tipoftheday.xcf
 create mode 100644 plugins/python/welcome/version.py
 create mode 100644 plugins/python/welcome/website.py
 delete mode 100644 src/gui/panels/welcome.c
 delete mode 100644 src/gui/panels/welcome.h

diff --git a/ChangeLog b/ChangeLog
index 3fa796a..99b1f7e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,42 @@
+15-09-01  Cyrille Bagard <nocbos@gmail.com>
+
+	* configure.ac:
+	Add the new Makefile from the 'plugins/python/welcome' directory.
+
+	* plugins/pychrysa/pychrysa.c:
+	Provide the revision number and a way to access global objects.
+
+	* plugins/python/Makefile.am:
+	Add 'welcome' to SUBDIRS.
+
+	* plugins/python/welcome/binary.py:
+	* plugins/python/welcome/board.py:
+	* plugins/python/welcome/__init__.py:
+	* plugins/python/welcome/Makefile.am:
+	* plugins/python/welcome/panel.py:
+	* plugins/python/welcome/plugin.py:
+	* plugins/python/welcome/tipoftheday.png:
+	* plugins/python/welcome/tipoftheday.png:
+	* plugins/python/welcome/tipoftheday.xcf:
+	* plugins/python/welcome/tipoftheday.xcf:
+	* plugins/python/welcome/tip.py:
+	* plugins/python/welcome/version.py:
+	* plugins/python/welcome/website.py:
+	New entries: add a welcome panel as plugin using Python.
+
+	* src/gui/menus/project.c:
+	Register the menu loading new binary files.
+
+	* src/gui/panels/Makefile.am:
+	Remove the 'welcome.[ch]' files from libguipanels_la_SOURCES.
+
+	* src/gui/panels/panel.c:
+	Update code.
+
+	* src/gui/panels/welcome.c:
+	* src/gui/panels/welcome.h:
+	Deleted entries.
+
 15-08-27  Cyrille Bagard <nocbos@gmail.com>
 
 	* plugins/pychrysa/gui/panels/panel.c:
diff --git a/configure.ac b/configure.ac
index a2ac711..d447047 100644
--- a/configure.ac
+++ b/configure.ac
@@ -289,6 +289,7 @@ AC_CONFIG_FILES([Makefile
                  plugins/python/apkfiles/Makefile
                  plugins/python/exectracer/Makefile
                  plugins/python/samples/Makefile
+                 plugins/python/welcome/Makefile
                  plugins/readelf/Makefile
                  plugins/ropgadgets/Makefile
                  plugins/stackvars/Makefile
diff --git a/plugins/pychrysa/pychrysa.c b/plugins/pychrysa/pychrysa.c
index eafb358..c77553b 100644
--- a/plugins/pychrysa/pychrysa.c
+++ b/plugins/pychrysa/pychrysa.c
@@ -228,6 +228,7 @@ bool init_plugin(GPluginModule *plugin, GObject *ref)
 
 
 #include <config.h>
+#include <common/cpp.h>
 #include <common/environment.h>
 #include <common/extstr.h>
 #include <plugins/plugin-def.h>
@@ -245,12 +246,18 @@ bool init_plugin(GPluginModule *plugin, GObject *ref)
 DEFINE_CHRYSALIDE_ACTIVE_PLUGIN("PyChrysalide", "Provides bindings to Python", "0.1.0", PGA_PLUGIN_INIT);
 
 
+/* Fournit la révision du programme global. */
+static PyObject *py_chrysalide_revision(PyObject *, PyObject *);
+
 /* Fournit la version du programme global. */
 static PyObject *py_chrysalide_version(PyObject *, PyObject *);
 
 /* Fournit la version du greffon pour Python. */
 static PyObject *py_chrysalide_mod_version(PyObject *, PyObject *);
 
+/* Recherche et fournit si elle existe une valeur globale. */
+static PyObject *py_chrysalide_get_global_gobject(PyObject *, PyObject *);
+
 /* Détermine si l'interpréteur lancé est celui pris en compte. */
 static bool is_current_abi_suitable(void);
 
@@ -264,7 +271,7 @@ static bool load_python_plugins(GPluginModule *plugin, GObject *);
 *  Paramètres  : self = NULL car méthode statique.                            *
 *                args = non utilisé ici.                                      *
 *                                                                             *
-*  Description : Fournit la version du programme global.                      *
+*  Description : Fournit la révision du programme global.                     *
 *                                                                             *
 *  Retour      : Numéro de révision.                                          *
 *                                                                             *
@@ -272,6 +279,26 @@ static bool load_python_plugins(GPluginModule *plugin, GObject *);
 *                                                                             *
 ******************************************************************************/
 
+static PyObject *py_chrysalide_revision(PyObject *self, PyObject *args)
+{
+    return PyUnicode_FromString("r" XSTR(REVISION));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = NULL car méthode statique.                            *
+*                args = non utilisé ici.                                      *
+*                                                                             *
+*  Description : Fournit la version du programme global.                      *
+*                                                                             *
+*  Retour      : Numéro de version.                                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
 static PyObject *py_chrysalide_version(PyObject *self, PyObject *args)
 {
     char version[16];
@@ -297,7 +324,7 @@ static PyObject *py_chrysalide_version(PyObject *self, PyObject *args)
 *                                                                             *
 *  Description : Fournit la version du greffon pour Python.                   *
 *                                                                             *
-*  Retour      : Numéro de révision.                                          *
+*  Retour      : Numéro de version.                                           *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
@@ -316,6 +343,41 @@ static PyObject *py_chrysalide_mod_version(PyObject *self, PyObject *args)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : self = NULL car méthode statique.                            *
+*                args = contient la clef d'accès à un champ particulier.      *
+*                                                                             *
+*  Description : Recherche et fournit si elle existe une valeur globale.      *
+*                                                                             *
+*  Retour      : Object attaché à l'espace de référencement global ou NULL.   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_chrysalide_get_global_gobject(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Instance à retourner        */
+    const char *key;                        /* Désignation du champ visé   */
+    int ret;                                /* Bilan de lecture des args.  */
+    void *data;                             /* Donnée quelconque           */
+
+    ret = PyArg_ParseTuple(args, "s", &key);
+    if (!ret) Py_RETURN_NONE;
+
+    data = g_object_get_data(get_internal_ref(), key);
+    if (data == NULL) Py_RETURN_NONE;
+
+    if (!G_IS_OBJECT(data)) Py_RETURN_NONE;
+
+    result = pygobject_new(G_OBJECT(data));
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : -                                                            *
 *                                                                             *
 *  Description : Détermine si l'interpréteur lancé est celui pris en compte.  *
@@ -410,13 +472,21 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
 
     static PyMethodDef py_chrysalide_methods[] = {
 
+        { "revision", py_chrysalide_revision,
+          METH_NOARGS,
+          "revision(/)\n--\n\nProvide the revision number of Chrysalide."
+        },
         { "version", py_chrysalide_version,
           METH_NOARGS,
-          "version(/)\n--\n\nProvide the revision number of Chrysalide."
+          "version(/)\n--\n\nProvide the version number of Chrysalide."
         },
         { "mod_version", py_chrysalide_mod_version,
           METH_NOARGS,
-          "mod_version(/)\n--\n\nProvide the revision number of Chrysalide module for Python."
+          "mod_version(/)\n--\n\nProvide the version number of Chrysalide module for Python."
+        },
+        { "get_global_gobject", py_chrysalide_get_global_gobject,
+          METH_VARARGS,
+          "get_global_gobject(key, /)\n--\n\nRetrieve if it exists a global GObject registered with the given key."
         },
         { NULL }
 
diff --git a/plugins/python/Makefile.am b/plugins/python/Makefile.am
index 7bb4122..f54e1be 100644
--- a/plugins/python/Makefile.am
+++ b/plugins/python/Makefile.am
@@ -1,2 +1,2 @@
 
-SUBDIRS = androperms apkfiles samples
+SUBDIRS = androperms apkfiles samples welcome
diff --git a/plugins/python/welcome/Makefile.am b/plugins/python/welcome/Makefile.am
new file mode 100644
index 0000000..7dd16fa
--- /dev/null
+++ b/plugins/python/welcome/Makefile.am
@@ -0,0 +1,14 @@
+
+welcomedir = $(datadir)/openida/plugins/python/welcome
+
+welcome_DATA =								\
+	__init__.py								\
+	binary.py								\
+	board.py								\
+	panel.py								\
+	plugin.py								\
+	tip.py									\
+	version.py								\
+	website.py								\
+	tipoftheday.png							\
+	tipoftheday.xcf
diff --git a/plugins/python/welcome/__init__.py b/plugins/python/welcome/__init__.py
new file mode 100644
index 0000000..00a76af
--- /dev/null
+++ b/plugins/python/welcome/__init__.py
@@ -0,0 +1,4 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from welcome.plugin import WelcomePlugin as AutoLoad
diff --git a/plugins/python/welcome/binary.py b/plugins/python/welcome/binary.py
new file mode 100644
index 0000000..a9b508d
--- /dev/null
+++ b/plugins/python/welcome/binary.py
@@ -0,0 +1,40 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from welcome.board import SmallBoard
+from gi.repository import Gtk, Gdk
+import pychrysalide
+
+
+class NewBinary(SmallBoard):
+    """Encourage l'ouverture d'un (premier) binaire."""
+
+
+    def __init__(self):
+        """Construit le panneau avec son contenu."""
+
+        super(NewBinary, self).__init__()
+
+        self._menu_item = pychrysalide.get_global_gobject('mnu_project_add_binary')
+
+        msg = 'Analyse a new binary by clicking <a href="file:///#">here</a>.'
+
+        desc = Gtk.Label(msg, use_markup=True, wrap=True)
+        desc.add_events(Gdk.EventMask.ENTER_NOTIFY_MASK)
+        desc.set_track_visited_links(False)
+        desc.connect('activate-link', self.on_link_activated)
+        self.add(desc)
+
+
+    def on_link_activated(self, uri, data):
+        """Lance l'action associée au lien représenté."""
+
+        self._menu_item.activate()
+
+        return True
+
+
+    def get_location(self):
+        """Fournit la localisation souhaitée pour la plache."""
+
+        return [ 0, 0, 1, 1 ]
diff --git a/plugins/python/welcome/board.py b/plugins/python/welcome/board.py
new file mode 100644
index 0000000..ebebbc3
--- /dev/null
+++ b/plugins/python/welcome/board.py
@@ -0,0 +1,102 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from gi.repository import Gtk
+
+
+class SmallBoard(Gtk.EventBox):
+    """Représente une tuile de support pour le panneau de bienvenue."""
+
+
+    css = """
+
+#classic {
+
+    border-color: rgba(255, 255, 255, 0.2);
+    border-style: solid;
+    border-width: 1px;
+
+}
+
+#hover {
+
+    border-color: rgba(255, 255, 255, 0.6);
+    border-style: solid;
+    border-width: 1px;
+
+}
+"""
+
+
+    def __init__(self):
+        """Construit le panneau avec son contenu."""
+
+        super(SmallBoard, self).__init__()
+
+        #self.set_size_request(250, 150)
+        self.set_has_window(True)
+
+        self.props.opacity = 0.6
+
+        self._manager = None
+
+
+    def on_enter(self, widget, event):
+        """Réagit à un survol de la zone par la souris."""
+
+        self.set_name('hover')
+
+        self._manager.define_selected_area(self.get_allocation())
+
+        self.props.opacity = 1.0
+
+        return False
+
+
+    def on_leave(self, widget, event):
+        """Réagit à une sortie de la zone par la souris."""
+
+        self.set_name('classic')
+
+        if self._manager != None:
+            self._manager.define_selected_area(None)
+
+        self.props.opacity = 0.6
+
+        return False
+
+
+    def get_location(self):
+        """Fournit la localisation souhaitée pour la plache."""
+
+        pass
+
+
+    def attach(self, manager):
+        """Lie partiellement la plache à son support et suit les survols."""
+
+        child = self.get_child()
+
+        if child != None:
+
+            child.props.margin = 20
+
+            self.set_name('classic')
+
+            self._manager = manager
+
+
+            def track_children(widget, owner):
+
+                widget.connect('enter-notify-event', self.on_enter)
+                widget.connect('leave-notify-event', self.on_leave)
+
+                if isinstance(widget, Gtk.Container):
+
+                    children = widget.get_children()
+
+                    for child in children:
+                        track_children(child, owner)
+
+
+            track_children(self, self)
diff --git a/plugins/python/welcome/panel.py b/plugins/python/welcome/panel.py
new file mode 100644
index 0000000..811f008
--- /dev/null
+++ b/plugins/python/welcome/panel.py
@@ -0,0 +1,147 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from welcome.binary import NewBinary
+from welcome.version import VersionChecker
+from welcome.website import WebInvitation
+from welcome.board import SmallBoard
+from welcome.tip import TipOfTheDay
+from gi.repository import GObject, Gtk, Gdk
+from pychrysalide.gui.panels import PanelItem
+
+
+class WelcomePanel(PanelItem):
+    """Display a welcome panel if nothing is open in the main part of the editor."""
+
+
+    def __init__(self):
+        """Initialize the Python instance of the panel."""
+
+        content = self._build_panel_content()
+
+        super(WelcomePanel, self).__init__('Welcome', 'First commands', content, 'M')
+
+
+    def _build_panel_content(self):
+        """Build content for the welcome panel."""
+
+        self._area = None
+
+        # Constitution du support principal
+
+        support = Gtk.Grid()
+
+        support.props.halign = Gtk.Align.CENTER
+        support.props.valign = Gtk.Align.CENTER
+        support.props.margin = 20
+
+        support.set_column_homogeneous(True)
+        support.set_row_homogeneous(True)
+        support.set_column_spacing(20)
+        support.set_row_spacing(20)
+
+        # Mise en place des différentes tuiles
+
+        cells = { }
+
+        for x in range(4):
+            for y in range(3):
+                cells[(x, y)] = False
+
+        tiles = [
+
+            NewBinary(),
+            VersionChecker(),
+            WebInvitation(),
+            TipOfTheDay()
+
+        ]
+
+        for t in tiles:
+
+            x, y, w, h = t.get_location()
+
+            for i in range(x, x + w):
+                for j in range(y, y + h):
+                    assert(cells[(i, j)] == False)
+                    cells[(i, j)] = True
+
+            t.attach(self)
+            support.attach(t, x, y, w, h)
+
+        for x in range(4):
+            for y in range(3):
+                if not cells[(x, y)]:
+                    tile = SmallBoard()
+                    tile.attach(self)
+                    support.attach(tile, x, y, 1, 1)
+
+        # Charge les styles propres aux panneaux
+
+        style_provider = Gtk.CssProvider()
+
+        style_provider.load_from_data(SmallBoard.css.encode())
+
+        Gtk.StyleContext.add_provider_for_screen(
+            Gdk.Screen.get_default(), 
+            style_provider,     
+            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
+        )
+
+
+        support.show_all()
+        return support
+
+
+    def define_selected_area(self, area):
+
+        self._area = area
+
+        ####
+        #self.queue_draw()
+
+
+    def draw_selected_area(self, widget, cr):
+
+
+        alloc = widget.get_allocation()
+
+
+
+
+        def draw_rounded2(cr, area, radius):
+            """ draws rectangles with rounded (circular arc) corners """
+            from math import pi
+            a,b,c,d=area
+            cr.arc(a + radius, c + radius, radius, 2*(pi/2), 3*(pi/2))
+            cr.arc(b - radius, c + radius, radius, 3*(pi/2), 4*(pi/2))
+            cr.arc(b - radius, d - radius, radius, 0*(pi/2), 1*(pi/2))  # ;o)
+            cr.arc(a + radius, d - radius, radius, 1*(pi/2), 2*(pi/2))
+            cr.rectangle(self._area.x, self._area.y, self._area.width, self._area.height)
+            cr.close_path()
+            cr.fill()
+
+
+        if self._area != None:
+            cr.set_source_rgba(0, 0, 0, 0.15)
+
+            border = 4
+
+            pts = ( self._area.x - border, self._area.x + self._area.width + border,
+                    self._area.y - border, self._area.y + self._area.height + border )
+
+            #cr.save()
+
+            draw_rounded2(cr, pts, 16)
+
+            ctx = self.get_style_context()
+
+
+            Gtk.render_background(ctx, cr, 0, 20, 100, 100)
+            Gtk.render_background(ctx, cr, self._area.x, self._area.y, self._area.width, self._area.height)
+
+
+            #cr.restore()
+
+
+        return False
diff --git a/plugins/python/welcome/plugin.py b/plugins/python/welcome/plugin.py
new file mode 100644
index 0000000..8a9f9a2
--- /dev/null
+++ b/plugins/python/welcome/plugin.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from pychrysalide import PluginModule
+from welcome.panel import WelcomePanel
+
+
+class WelcomePlugin(PluginModule):
+    """Interface graphique d'accueil."""
+
+
+    def get_interface(self):
+        """Provide the full plugin description."""
+
+        desc = {
+
+            'name' : 'Welcome',
+            'desc' : 'Introduce the software when no project is loaded',
+            'version' : '0.1',
+
+            'actions' : [ PluginModule.PGA_PLUGIN_INIT ]
+
+        }
+
+        return desc
+
+
+    def init(self, ref):
+        """Initialise l'extension."""
+
+        self._panel = WelcomePanel()
+
+        self._panel.dock()
+        self._panel.register()
+
+        return True
diff --git a/plugins/python/welcome/tip.py b/plugins/python/welcome/tip.py
new file mode 100644
index 0000000..1a57575
--- /dev/null
+++ b/plugins/python/welcome/tip.py
@@ -0,0 +1,146 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from welcome.board import SmallBoard
+from gi.repository import Gtk
+import random
+
+try:
+    import cairo
+    has_cairo = True
+    import os
+except:
+    has_cairo = False
+
+
+_tip_messages = [
+    "Message 1",
+    "Message 2",
+    "Message 3",
+    "Message 4",
+    "Message 5",
+    "Message 6"
+]
+
+assert(len(_tip_messages) > 0)
+
+
+class TipOfTheDay(SmallBoard):
+    """Présente une série d'astuces du jour."""
+
+
+    def __init__(self):
+        """Construit le panneau avec son contenu."""
+
+        super(TipOfTheDay, self).__init__()
+
+        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
+        self.add(box)
+
+        # Barre de contrôle
+
+        toolbar = Gtk.Box(spacing=10)
+        toolbar.props.margin = 20
+        box.pack_end(toolbar, False, True, 0)
+
+        btn = Gtk.Button('Previous')
+        btn.connect('clicked', self.show_previous_message)
+        toolbar.pack_start(btn, False, True, 8)
+
+        btn = Gtk.Button('Next')
+        btn.connect('clicked', self.show_next_message)
+        toolbar.pack_start(btn, False, True, 8)
+
+        # Contenu de l'astuce courante
+
+        desc = Gtk.Label('', use_markup=True, wrap=True, xalign=0)
+        self._message = desc
+        desc.set_justify(Gtk.Justification.LEFT)
+        box.pack_end(desc, False, True, 0)
+
+        # Titre
+
+        desc = Gtk.Label("<b>Did you know?</b>", use_markup=True, wrap=True, xalign=0)
+        desc.set_justify(Gtk.Justification.LEFT)
+        box.pack_end(desc, False, True, 0)
+
+        # Image de fond, si possible
+
+        if has_cairo:
+
+            os.chdir(os.path.dirname(__file__))
+
+            self._img = cairo.ImageSurface.create_from_png('tipoftheday.png')
+
+            self.connect_after('draw', self.draw_background)
+
+        # Sélection du message courant
+
+        self._indexes = [i for i in range(len(_tip_messages))]
+        random.shuffle(self._indexes)
+
+        self._index = 0
+
+        self.show_message()
+
+
+    def draw_background(self, widget, cr):
+        """Dessine une image de fond pour les conseils."""
+
+        img_width = self._img.get_width()
+        img_height = self._img.get_height()
+
+        alloc = self.get_allocation()
+        target_height = alloc.height * 0.7
+
+        if img_height > target_height:
+
+            scale = float(target_height) / float(img_height)
+
+            cr.translate(alloc.width - img_width * scale - 10, 10)
+            cr.scale(scale, scale)
+
+        else:
+
+            cr.translate(alloc.width - img_width - 10, 10)
+
+        cr.set_source_surface(self._img)
+        cr.paint_with_alpha(0.6)
+
+
+    def show_message(self):
+        """Affiche un conseil du jour donné."""
+
+        selected = self._indexes[self._index]
+
+        msg = _tip_messages[selected]
+
+        self._message.set_markup(msg)
+
+
+    def show_previous_message(self, button):
+        """Affiche un conseil du jour précédent."""
+
+        if self._index == 0:
+            self._index = len(_tip_messages) - 1
+        else:
+            self._index = self._index - 1
+
+        self.show_message()
+
+
+    def show_next_message(self, button):
+        """Affiche un conseil du jour suivant."""
+
+        self._index = self._index + 1
+
+        if self._index == len(_tip_messages):
+            self._index = 0
+
+        self.show_message()
+
+
+    def get_location(self):
+        """Fournit la localisation souhaitée pour la plache."""
+
+        return [ 2, 1, 2, 2 ]
diff --git a/plugins/python/welcome/tipoftheday.png b/plugins/python/welcome/tipoftheday.png
new file mode 100644
index 0000000..12f017a
Binary files /dev/null and b/plugins/python/welcome/tipoftheday.png differ
diff --git a/plugins/python/welcome/tipoftheday.xcf b/plugins/python/welcome/tipoftheday.xcf
new file mode 100644
index 0000000..dc9cf06
Binary files /dev/null and b/plugins/python/welcome/tipoftheday.xcf differ
diff --git a/plugins/python/welcome/version.py b/plugins/python/welcome/version.py
new file mode 100644
index 0000000..37ba001
--- /dev/null
+++ b/plugins/python/welcome/version.py
@@ -0,0 +1,107 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from welcome.board import SmallBoard
+from gi.repository import Gtk
+import pychrysalide
+
+try:
+    import urllib3
+    has_urllib3 = True
+except:
+    has_urllib3 = False
+
+
+class VersionChecker(SmallBoard):
+    """Affichage des versions courante et disponible, ainsi que des conclusions associées."""
+
+
+    def __init__(self):
+        """Construit le panneau avec son contenu."""
+
+        super(VersionChecker, self).__init__()
+
+        current = pychrysalide.revision()
+
+        if has_urllib3:
+
+            lastest = self.get_lastest_version('community')            
+            up2date = self.get_update_status(current, lastest)
+
+            if lastest != None and up2date != None:
+
+                msg = '''Your version is: <b>%s</b>
+
+Lastest version is: <b>%s</b>'''
+
+                caption = msg % (current, lastest if lastest != None else 'unknown')
+
+                if up2date:
+                    caption = caption + '''
+
+Your software is <span color='green'><b>up-to-date</b></span>.'''
+                else:
+                    caption = caption + '''
+
+Your software is <b><span color='red'>outdated</span></b>.'''
+
+            else:
+
+                msg = '''Your version is: <b>%s</b>
+            
+An error occurred while dealing with revision numbers.'''
+
+                caption = msg % current
+
+        else:
+
+            msg = '''Your version is: <b>%s</b>
+
+To display the lastest available version, please install the <b>urllib3</b> package for Python.'''
+
+            caption = msg % current
+
+        desc = Gtk.Label(caption, use_markup=True, wrap=True)
+        desc.set_track_visited_links(False)
+        self.add(desc)
+
+
+    def get_lastest_version(self, category):
+        """Retrouve la dernière version disponible à partir du site officiel."""
+
+        lastest = None
+
+        http = urllib3.PoolManager()
+        request = http.request('GET', 'http://localhost/mediawiki/data/versions')
+
+        html = request.data.decode('utf-8')
+
+        request.release_conn()
+
+        available = html.split('\n')
+
+        for a in available:
+            desc = a.split('=')
+            if desc[0] == category:
+                lastest = desc[1]
+                break
+
+        return lastest
+
+
+    def get_update_status(self, current, lastest):
+        """Détermine le degré de mise à jour du système."""
+
+        if current[0] != 'r' or lastest[0] != 'r':
+            return None
+
+        cur_rev = int(current[1:])
+        last_rev = int(lastest[1:])
+
+        return (cur_rev >= last_rev)
+
+
+    def get_location(self):
+        """Fournit la localisation souhaitée pour la plache."""
+
+        return [ 2, 0, 1, 1 ]
diff --git a/plugins/python/welcome/website.py b/plugins/python/welcome/website.py
new file mode 100644
index 0000000..07c2016
--- /dev/null
+++ b/plugins/python/welcome/website.py
@@ -0,0 +1,30 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from welcome.board import SmallBoard
+from gi.repository import Gtk, Gdk
+
+
+class WebInvitation(SmallBoard):
+    """Présente un lien rapide vers le site Web officiel."""
+
+
+    def __init__(self):
+        """Construit le panneau avec son contenu."""
+
+        super(WebInvitation, self).__init__()
+
+        msg = '''Get access to the online documentation and stay tuned by visiting the official website :
+
+<a href="http://0xdeadc0de.fr/chrysalide/">0xdeadc0de.fr/chrysalide</a>'''
+
+        desc = Gtk.Label(msg, use_markup=True, wrap=True)
+        desc.add_events(Gdk.EventMask.ENTER_NOTIFY_MASK)
+        desc.set_track_visited_links(False)
+        self.add(desc)
+
+
+    def get_location(self):
+        """Fournit la localisation souhaitée pour la plache."""
+
+        return [ 3, 0, 1, 1 ]
diff --git a/src/gui/menus/project.c b/src/gui/menus/project.c
index caf3f64..a68b137 100644
--- a/src/gui/menus/project.c
+++ b/src/gui/menus/project.c
@@ -87,7 +87,7 @@ GtkWidget *build_menu_project(GObject *ref, GtkAccelGroup *accgroup, GMenuBar *b
                                         G_CALLBACK(mcb_project_add_shellcode), bar);
     gtk_container_add(GTK_CONTAINER(deepmenubar), deepmenuitem);
 
-    deepmenuitem = qck_create_menu_item(NULL, NULL, _("File"),
+    deepmenuitem = qck_create_menu_item(ref, "mnu_project_add_binary", _("File"),
                                         G_CALLBACK(mcb_project_add_binary_file), bar);
     gtk_container_add(GTK_CONTAINER(deepmenubar), deepmenuitem);
 
diff --git a/src/gui/panels/Makefile.am b/src/gui/panels/Makefile.am
index 70cf597..4746210 100644
--- a/src/gui/panels/Makefile.am
+++ b/src/gui/panels/Makefile.am
@@ -9,8 +9,7 @@ libguipanels_la_SOURCES =				\
 	panel.h panel.c						\
 	regedit.h regedit.c					\
 	strings.h strings.c					\
-	symbols.h symbols.c					\
-	welcome.h welcome.c
+	symbols.h symbols.c
 
 libguipanels_la_LDFLAGS = 
 
diff --git a/src/gui/panels/panel.c b/src/gui/panels/panel.c
index 7f18fea..265fcca 100644
--- a/src/gui/panels/panel.c
+++ b/src/gui/panels/panel.c
@@ -38,7 +38,6 @@
 #include "regedit.h"
 #include "strings.h"
 #include "symbols.h"
-#include "welcome.h"
 #include "../../gtkext/easygtk.h"
 #include "../../gtkext/gtkdockable-int.h"
 #include "../../gtkext/gtkdockstation.h"
@@ -58,7 +57,6 @@ static GCallback _handler;
 static gpointer _data;
 
 /* Liste des panneaux en place. */
-static GPanelItem *_welcome = NULL;
 static GPanelItem *_panels_list = NULL;
 
 
@@ -133,13 +131,6 @@ static void set_panel_node_size_request(const panel_node *, const GtkRequisition
 
 
 
-/* Surveille les ajouts dans la partie principale. */
-static void on_docking_to_main_panel(GtkDockStation *, GtkWidget *, gpointer);
-
-
-
-
-
 
 /* Indique le type défini pour un élément destiné à un panneau. */
 G_DEFINE_TYPE_WITH_CODE(GPanelItem, g_panel_item, G_TYPE_EDITOR_ITEM,
@@ -465,12 +456,6 @@ void load_main_panels(GObject *ref)
 {
     GPanelItem *item;                       /* Panneau de base à charger   */
 
-    _welcome = create_welcome_panel(ref);
-    g_panel_item_dock(_welcome);
-
-    g_signal_connect(_nodes->station, "dock-widget",
-                     G_CALLBACK(on_docking_to_main_panel), NULL);
-
     item = create_regedit_panel(ref);
     g_panel_item_dock(item);
 
@@ -1154,46 +1139,3 @@ static void set_panel_node_size_request(const panel_node *node, const GtkRequisi
     set_panel_node_size_request(node->second, ALLOC_2_REQ(&allocation));
 
 }
-
-
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/*                        MECANISMES DE PLACEMENT DES PANNEAUX                        */
-/* ---------------------------------------------------------------------------------- */
-
-
-
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : station = base d'accueil pour composants divers.             *
-*                widget  = composant rajouté à l'ensemble.                    *
-*                data    = adresse non utilisée ici.                          *
-*                                                                             *
-*  Description : Surveille les ajouts dans la partie principale.              *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void on_docking_to_main_panel(GtkDockStation *station, GtkWidget *widget, gpointer data)
-{
-
-
-
-
-    g_panel_item_undock(_welcome);
-
-
-
-    g_signal_handlers_disconnect_by_func(station,
-                                         G_CALLBACK(on_docking_to_main_panel), NULL);
-
-
-}
-
diff --git a/src/gui/panels/welcome.c b/src/gui/panels/welcome.c
deleted file mode 100644
index fa55fd7..0000000
--- a/src/gui/panels/welcome.c
+++ /dev/null
@@ -1,173 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * welcome.c - panneau d'affichage d'accueil
- *
- * Copyright (C) 2012-2014 Cyrille Bagard
- *
- *  This file is part of Chrysalide.
- *
- *  OpenIDA is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  OpenIDA is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-
-#include "welcome.h"
-
-
-#include <string.h>
-#include <gtk/gtk.h>
-
-
-#include "panel-int.h"
-#include "../../gtkext/easygtk.h"
-#include "../../gtkext/support.h"
-
-
-
-/* -------------------------- PARTIE PRINCIPALE DU PANNEAU -------------------------- */
-
-
-/* Panneau d'accueil (instance) */
-struct _GWelcomePanel
-{
-    GPanelItem parent;                      /* A laisser en premier        */
-
-};
-
-
-/* Panneau d'accueil (classe) */
-struct _GWelcomePanelClass
-{
-    GPanelItemClass parent;                 /* A laisser en premier        */
-
-};
-
-
-/* Initialise la classe des panneaux d'accueil. */
-static void g_welcome_panel_class_init(GWelcomePanelClass *);
-
-/* Initialise une instance de panneau d'accueil. */
-static void g_welcome_panel_init(GWelcomePanel *);
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/*                            PARTIE PRINCIPALE DU PANNEAU                            */
-/* ---------------------------------------------------------------------------------- */
-
-
-/* Indique le type définit pour un panneau d'accueil. */
-G_DEFINE_TYPE(GWelcomePanel, g_welcome_panel, G_TYPE_PANEL_ITEM);
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : klass = classe à initialiser.                                *
-*                                                                             *
-*  Description : Initialise la classe des panneaux d'accueil.                 *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_welcome_panel_class_init(GWelcomePanelClass *klass)
-{
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : panel = instance à initialiser.                              *
-*                                                                             *
-*  Description : Initialise une instance de panneau d'accueil.                *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_welcome_panel_init(GWelcomePanel *panel)
-{
-    GtkWidget *align;                       /* Alignement centré           */
-    gchar *filename;                        /* Chemin d'accès au fichier   */
-    GtkWidget *image;                       /* Image chargée               */
-    GEditorItem *base;                      /* Version basique d'instance  */
-
-    align = gtk_alignment_new(0.5f, 0.5f, 0.0f, 0.0f);
-    gtk_widget_show(align);
-
-    filename = find_pixmap_file("welcome.png");
-    image = qck_create_image(NULL, NULL, filename);
-    gtk_container_add(GTK_CONTAINER(align), image);
-
-    base = G_EDITOR_ITEM(panel);
-    base->widget = align;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : ref = espace de référencement global.                        *
-*                                                                             *
-*  Description : Crée un panneau d'accueil.                                   *
-*                                                                             *
-*  Retour      : Adresse de la structure mise en place.                       *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-GEditorItem *g_welcome_panel_new(GObject *ref)
-{
-    GEditorItem *result;                    /* Structure à retourner       */
-
-    result = g_object_new(G_TYPE_WELCOME_PANEL, NULL);
-
-    g_panel_item_init_ext(G_PANEL_ITEM(result), ref, PANEL_WELCOME_ID,
-                          _("Welcome"), G_EDITOR_ITEM(result)->widget, "M");
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : ref = espace de référencement global.                        *
-*                                                                             *
-*  Description : Construit et intègre un panneau d'accueil.                   *
-*                                                                             *
-*  Retour      : Adresse du panneau mis en place.                             *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-GPanelItem *create_welcome_panel(GObject *ref)
-{
-    GEditorItem *result;                    /* Elément réactif à renvoyer  */
-
-    result = g_welcome_panel_new(ref);
-
-    /* Enregistre correctement le tout */
-    register_editor_item(result);
-
-    return G_PANEL_ITEM(result);
-
-}
diff --git a/src/gui/panels/welcome.h b/src/gui/panels/welcome.h
deleted file mode 100644
index 88c17bd..0000000
--- a/src/gui/panels/welcome.h
+++ /dev/null
@@ -1,65 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * welcome.h - prototypes pour le panneau d'affichage d'accueil
- *
- * Copyright (C) 2012 Cyrille Bagard
- *
- *  This file is part of Chrysalide.
- *
- *  OpenIDA is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  OpenIDA is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-
-#ifndef _GUI_PANELS_WELCOME_H
-#define _GUI_PANELS_WELCOME_H
-
-
-#include <i18n.h>
-
-
-#include "panel.h"
-
-
-
-#define PANEL_WELCOME_ID _("Welcome")
-
-
-#define G_TYPE_WELCOME_PANEL               g_welcome_panel_get_type()
-#define G_WELCOME_PANEL(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_welcome_panel_get_type(), GWelcomePanel))
-#define G_IS_WELCOME_PANEL(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_welcome_panel_get_type()))
-#define G_WELCOME_PANEL_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WELCOME_PANEL, GWelcomePanelClass))
-#define G_IS_WELCOME_PANEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WELCOME_PANEL))
-#define G_WELCOME_PANEL_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WELCOME_PANEL, GWelcomePanelClass))
-
-
-/* Panneau d'accueil (instance) */
-typedef struct _GWelcomePanel GWelcomePanel;
-
-/* Panneau d'accueil (classe) */
-typedef struct _GWelcomePanelClass GWelcomePanelClass;
-
-
-/* Indique le type définit pour un panneau d'accueil. */
-GType g_welcome_panel_get_type(void);
-
-/* Crée un panneau d'accueil. */
-GEditorItem *g_welcome_panel_new(GObject *);
-
-/* Construit et intègre un panneau d'accueil. */
-GPanelItem *create_welcome_panel(GObject *);
-
-
-
-#endif  /* _GUI_PANELS_WELCOME_H */
-- 
cgit v0.11.2-87-g4458