summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2015-09-01 21:36:22 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2015-09-01 21:36:22 (GMT)
commit29ddd755496589e7e1f9e38697e44d3cfe64df5e (patch)
tree3db093a9082276adb96a1ce67d175ade067c0788 /plugins
parente07a541d1dea13a19a587f2b97d12ed3443f235b (diff)
Added a welcome panel as plugin using Python.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@573 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'plugins')
-rw-r--r--plugins/pychrysa/pychrysa.c78
-rw-r--r--plugins/python/Makefile.am2
-rw-r--r--plugins/python/welcome/Makefile.am14
-rw-r--r--plugins/python/welcome/__init__.py4
-rw-r--r--plugins/python/welcome/binary.py40
-rw-r--r--plugins/python/welcome/board.py102
-rw-r--r--plugins/python/welcome/panel.py147
-rw-r--r--plugins/python/welcome/plugin.py36
-rw-r--r--plugins/python/welcome/tip.py146
-rw-r--r--plugins/python/welcome/tipoftheday.pngbin0 -> 10206 bytes
-rw-r--r--plugins/python/welcome/tipoftheday.xcfbin0 -> 17942 bytes
-rw-r--r--plugins/python/welcome/version.py107
-rw-r--r--plugins/python/welcome/website.py30
13 files changed, 701 insertions, 5 deletions
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
--- /dev/null
+++ b/plugins/python/welcome/tipoftheday.png
Binary files differ
diff --git a/plugins/python/welcome/tipoftheday.xcf b/plugins/python/welcome/tipoftheday.xcf
new file mode 100644
index 0000000..dc9cf06
--- /dev/null
+++ b/plugins/python/welcome/tipoftheday.xcf
Binary files 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 ]