X. Avant-propos▲
L'article touche à sa fin. Edje et Elementary ont été suffisamment détaillés pour que tout lecteur puisse se lancer sérieusement dans le développement d'applications utilisant les EFL. Toutefois, abandonner ainsi un lecteur sans donner d'exemple complet ne serait pas forcément judicieux. C'est pour cela que cette partie de l'article développera la conception progressive d'un navigateur Web développé avec Webkit et les EFL grâce au port EFL du projet Webkit.
XI. Installation de Webkit-EFL▲
Pour les distributions telles qu'Ubuntu, afin d'installer Webkit pour les EFL, soyez sûr d'avoir les paquets suivants :
sudo apt-get install cmake libicu-dev libxslt-dev libsqlite3-dev gperf \
libxt-dev libfontconfig1-dev libcairo2-dev libglib2.0-dev libgtk2.0-dev \
libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev libcurl4-dev
Liste initialement en provenance de http://trac.webkit.org/wiki/EFLWebKit.
Cela fait, on récupère les sources, que l'on place par exemple dans /home/username :
cd /home/username/
svn checkout http://svn.webkit.org/repository/webkit/trunk WebKit
L'opération peut prendre un certain temps. La procédure terminée, on suit les informations de la page citée ci-dessus:
cd WebKit/
mkdir build
cd build/
On lance alors CMake puis on compile :
cmake ../Source -DPORT=Efl -DNETWORK_BACKEND=curl -DSHARED_CORE=OFF -DCMAKE_BUILD_TYPE=Release
make && make install
Une fois de plus, cela peut prendre du temps.
XII. Création du navigateur▲
XII-A. Utilisation de Webkit-EFL avec Elementary▲
Maintenant que le Webkit est installé avec son port des EFL, il est temps de l'utiliser. Voici donc le code minimal de la partie :
#include <Elementary.h>
#include <EWebKit.h>
static
void
win_del
(
void
*
data, Evas_Object *
obj, void
*
event_info)
{
elm_exit
(
);
}
EAPI int
elm_main
(
int
argc, char
**
argv)
{
Evas_Object *
win;
ewk_init
(
); // Initialisation de WebKit.
win =
elm_win_add
(
NULL
, "
main_window
"
, ELM_WIN_BASIC);
elm_win_title_set
(
win, "
Elementary
"
);
evas_object_smart_callback_add
(
win, "
delete,request
"
, win_del, NULL
);
// On créera ici notre navigateur.
evas_object_resize
(
win, 800
, 600
);
evas_object_show
(
win);
elm_run
(
);
ewk_shutdown
(
); // Fermeture de WebKit.
elm_shutdown
(
);
return
EXIT_SUCCESS;
}
ELM_MAIN
(
)
Comme dit dans les commentaires, les fonctions ewk_init() et ewk_shutdown() sont respectivement utilisées pour initialiser et fermer WebKit. Par le biais de EWebKit.h, on dispose de tout ce que WebKit met à disposition pour son déploiement avec les EFL.
Pour compiler le code donné ci-dessus et les suivants, la commande est la suivante :
gcc -o webkit webkit.c \
-DEWK_DATADIR="\"$(pkg-config ewebkit --variable=datadir)\"" \
`pkg-config elementary ewebkit --cflags --libs`
Dans le cas où libewebkit.so.0 serait introuvable, une copie à côté de l'exécutable de ce fichier et de libewebkit.so.0.1.0 depuis /usr/local/lib/ est suffisante.
Pour créer un navigateur, WebKit met à disposition la fonction ewk_view_single_add() qui prend pour argument un objet Evas (et non Elementary) et qui retourne un Evas_Object. Puisque Elementary, et non directement Evas, est utilisée pour créer la fenêtre principale, il est nécessaire de récupérer un objet Evas de l'objet Elementary :
Evas_Object *
win;
Evas *
e;
...
e =
evas_object_evas_get
(
win);
Dès lors, on peut créer notre navigateur avec ewk_view_single_add() en lui passant l'objet Evas e, définir le thème avec ewk_view_theme_set() et la page à afficher avec ewk_view_uri_set() :
#define EWK_THEME EWK_DATADIR"/themes/default.edj"
...
Evas_Object *
win, *
browser;
Evas *
e;
...
e =
evas_object_evas_get
(
win);
browser =
ewk_view_single_add
(
e);
ewk_view_theme_set
(
browser, EWK_THEME);
ewk_view_uri_set
(
browser, "
http://www.developpez.com/
"
);
elm_win_resize_object_add
(
win, browser);
evas_object_show
(
browser) ;
Après compilation, le résultat est le suivant :
XII-B. Une interface graphique plus esthétique▲
Il est alors nécessaire d'offrir à l'utilisateur une interface plus jolie ainsi que plus d'outils afin de lui permettre d'interagir avec le navigateur par le biais d'une barre d'adresse ainsi que des boutons « Précédent », « Suivant », etc. Pour cela, un simple fichier Edje va permettre un gain de temps.
#define MIN 24
#define MAX 24
#define TOP_BUTTON(_name, _prev) \
part {
\
name
:
_name; \
type
:
EXTERNAL; \
source
:
"
elm/button
"
; \
description {
\
state
:
"
default
"
0
.0
; \
align
:
0
0
; \
min
:
MIN MIN; \
max
:
MAX MAX; \
params {
\
string
:
"
icon
"
_name; \
}
\
rel1 {
\
to_x
:
_prev; \
offset
:
MAX+
15
0
; \
}
\
}
\
}
\
#define TOP_PROGRAM(_name) \
program {
\
name
:
_name"
_clicked
"
; \
signal
:
"
clicked
"
; \
source
:
_name; \
action
:
SIGNAL_EMIT _name"
,clicked
"
""
; \
}
\
collections {
group {
name
:
"
top_group
"
;
externals {
external
:
"
elm
"
;
}
parts {
part {
name
:
"
back
"
;
type
:
EXTERNAL;
source
:
"
elm/button
"
;
description {
state
:
"
default
"
0
.0
;
align
:
0
0
;
min
:
MIN MIN;
max
:
MAX MAX;
params {
string
:
"
icon
"
"
back
"
;
}
rel1 {
relative
:
0
0
;
offset
:
0
0
;
}
}
}
TOP_BUTTON
(
"
forward
"
, "
back
"
);
TOP_BUTTON
(
"
reload
"
, "
forward
"
);
TOP_BUTTON
(
"
stop
"
, "
reload
"
);
TOP_BUTTON
(
"
go-jump
"
, "
stop
"
);
part {
name
:
"
url
"
;
type
:
EXTERNAL;
source
:
"
elm/scrolled_entry
"
;
description {
state
:
"
default
"
0
.0
;
align
:
0
0
;
rel1 {
to_x
:
"
go-jump
"
;
offset
:
MAX+
15
0
;
}
params {
bool
:
"
editable
"
1
;
bool
:
"
single line
"
1
;
}
}
}
}
programs {
TOP_PROGRAM
(
"
back
"
);
TOP_PROGRAM
(
"
forward
"
);
TOP_PROGRAM
(
"
reload
"
);
TOP_PROGRAM
(
"
stop
"
);
TOP_PROGRAM
(
"
go-jump
"
);
}
}
}
On peut constater que l'utilisation de macro a permis de condenser grandement le code. Il s'agit maintenant d'améliorer l'interface graphique. Afin d'aboutir à un rendu plus correct, on va utiliser le fichier Edje et divers widgets, comme des séparateurs, barres de progression ou encore boîtes :
Evas_Object *
win, *
background, *
box, *
separator, *
top, *
browser, *
progressbar;
...
ewk_init
(
);
win =
elm_win_add
(
NULL
, "
main_window
"
, ELM_WIN_BASIC);
elm_win_title_set
(
win, "
Elementary
"
);
evas_object_smart_callback_add
(
win, "
delete,request
"
, win_del, NULL
);
background =
elm_bg_add
(
win);
elm_win_resize_object_add
(
win, background);
evas_object_size_hint_weight_set
(
background, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_show
(
background);
box =
elm_box_add
(
win);
elm_win_resize_object_add
(
win, box);
evas_object_size_hint_weight_set
(
box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_show
(
box);
top =
elm_layout_add
(
win);
elm_layout_file_set
(
top, "
top.edj
"
, "
top_group
"
);
evas_object_size_hint_weight_set
(
top, EVAS_HINT_EXPAND, 0
);
evas_object_size_hint_align_set
(
top, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_box_pack_end
(
box, top);
evas_object_show
(
top);
separator =
elm_separator_add
(
win);
elm_separator_horizontal_set
(
separator, 1
);
elm_box_pack_end
(
box, separator);
evas_object_show
(
separator);
e =
evas_object_evas_get
(
win);
browser =
ewk_view_single_add
(
e);
ewk_view_theme_set
(
browser, EWK_THEME);
ewk_view_uri_set
(
browser, "
http://www.developpez.com/
"
);
evas_object_size_hint_weight_set
(
browser, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set
(
browser, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_box_pack_end
(
box, browser);
evas_object_show
(
browser);
separator =
elm_separator_add
(
win);
elm_separator_horizontal_set
(
separator, 1
);
elm_box_pack_end
(
box, separator);
evas_object_show
(
separator);
progressbar =
elm_progressbar_add
(
win);
evas_object_size_hint_weight_set
(
progressbar, EVAS_HINT_EXPAND, 0
);
evas_object_size_hint_align_set
(
progressbar, EVAS_HINT_FILL, 0
.5
);
elm_box_pack_end
(
box, progressbar);
evas_object_show
(
progressbar);
...
Jusque-là, rien de nouveau. On a juste utilisé une petite panoplie de widgets afin de réaliser l'interface.
Ce n'est pas encore la dernière version de Google Chrome ou de Firefox, mais ça ressemble un minimum à quelque chose. Du moins, les options de navigation sont là, plus qu'à les relier au navigateur.
XII-C. Les callbacks▲
L'interface graphique étant faite, la pièce manquante du puzzle est les différents callbacks qui vont la relier au navigateur.
Sur le point de la gestion des signaux Edje, les boutons « Précédent », « Suivant », « Stop » et « Actualiser » devront exercer leur tâche sur le navigateur, le bouton « Go » devra charger la page demandée dans la barre d'adresse. De même, pour la gestion des évènements du navigateur, la barre de progression devra changer de valeur au fur et à mesure que la page sera chargée et la barre d'adresse devra s'adapter à un changement d'adresse.
// Callbacks de top.edj :
edje =
elm_layout_edje_get
(
top);
edje_object_signal_callback_add
(
edje, "
back,clicked
"
, "
*
"
, event_handler, (
void
*
)browser);
edje_object_signal_callback_add
(
edje, "
forward,clicked
"
, "
*
"
, event_handler, (
void
*
)browser);
edje_object_signal_callback_add
(
edje, "
reload,clicked
"
, "
*
"
, event_handler, (
void
*
)browser);
edje_object_signal_callback_add
(
edje, "
stop,clicked
"
, "
*
"
, event_handler, (
void
*
)browser);
edje_object_signal_callback_add
(
edje, "
go-jump,clicked
"
, "
*
"
, event_handler, (
void
*
)browser);
La seule chose à noter est que nous passons le navigateur en argument pour pouvoir interagir avec lui dans la fonction event_handler(), de prototype :
void
event_handler
(
void
*
data, Evas_Object *
obj, const
char
*
emission, const
char
*
source)
Ici, data va donner accès à notre pointeur browser, et obj à notre pointeur edje, conformément aux arguments donnés dans edje_object_signal_callback_add().
void
event_handler
(
void
*
data, Evas_Object *
obj, const
char
*
emission, const
char
*
source)
{
// Précédent :
if
(!
strcmp
(
emission, "
back,clicked
"
))
ewk_view_back
(
data);
// Suivant :
if
(!
strcmp
(
emission, "
forward,clicked
"
))
ewk_view_forward
(
data);
// Actualiser :
if
(!
strcmp
(
emission, "
reload,clicked
"
))
ewk_view_reload
(
data);
// Arrêter :
if
(!
strcmp
(
emission, "
stop,clicked
"
))
ewk_view_stop
(
data);
// Go :
if
(!
strcmp
(
emission, "
go-jump,clicked
"
))
{
Edje_External_Param param =
{
"
text
"
, EDJE_EXTERNAL_PARAM_TYPE_STRING, 0
, 0
, NULL
}
;
// On récupère les paramètres de l'élément de nom url...
if
(
edje_object_part_external_param_get
(
obj, "
url
"
, &
param))
ewk_view_uri_set
(
data, param.s); // ... dont son texte, dans param.s.
}
}
Toutes les fonctions utilisées dans le code ci-dessus sont documentées dans le fichier ewk_view.cpp, situé par défaut dans /home/username/WebKit/efl/ewk/.
Note : il existe une solution plus simple permettant de gérer le bouton « Go ». Elle consiste en une récupération de l'élément Edje avec edje_object_part_external_object_get() puis de l'utilisation d'une fonction d'Elementary, elm_scrolled_entry_entry_get() sur l'objet ainsi récupéré. Au final, on obtient un const char*, que l'on peut passer à la fonction ewk_view_uri_set() pour effectuer la même chose que dans le code donné. Cette solution sera étudiée plus loin.
Les signaux en provenance d'Edje sont donc gérés. Plus qu'à écrire les callbacks des signaux en provenance du navigateur, dont la liste exhaustive se trouve également dans ewk_view.cpp. Dans le cas présent, les callbacks suivants vont être utilisés :
// Callbacks du browser :
evas_object_smart_callback_add
(
browser, "
uri,changed
"
, b_url_changed, (
void
*
)edje);
evas_object_smart_callback_add
(
browser, "
load,progress
"
, b_load_progress, (
void
*
)progressbar);
Avec le prototype de fonction callback suivant :
void
callback
(
void
*
data, Evas_Object *
obj, void
*
event_info)
On a :
- uri,changed est appelé quand le navigateur change d'url (le pointeur event_info contiendra une chaîne de caractères correspondant à la nouvelle adresse) ;
- load,progress est appelé quand le navigateur est en train de charger une page (le pointeur event_info contiendra un nombre entre 0 et 1 correspondant à l'avancement du chargement).
L'
implémentation peut donc être faite.
void
b_uri_changed(void *data, Evas_Object *obj, void *event_info)
{
// event_info contient la nouvelle adresse.
Evas_Object *ext_url = edje_object_part_external_object_get(data, "url");
if (!ext_url)
return;
elm_scrolled_entry_entry_set(ext_url, (char*)event_info);
}
void
b_load_progress(void *data, Evas_Object *obj, void *event_info)
{
// event_info contient la progression entre 0.0 et 1.0.
elm_progressbar_value_set(data, *(double*)(event_info));
}
Dans b_uri_changed(), on commence par récupérer un Evas_Object* de l'élément url de l'Edje puis on utilise elm_scrolled_entry_entry_set() pour définir le texte. C'est l'autre méthode par référence à celle présentée pour la gestion du bouton « Go ».
Après compilation, le navigateur fonctionne très bien.
Ainsi se termine cette partie ainsi que l'article. Par le biais de cet exemple, de nombreuses notions ont été approfondies et certains éléments ont été introduits. Toutefois, il n'est jamais inutile d'aller creuser un peu plus dans la documentation et/ou dans les fichiers sources dans le but d'améliorer un exemple ou tout simplement pour se lancer dans un projet, qu'il soit petit ou gros. WebKit est un projet vaste qui ne se limite pas à des actions simples. La gestion des paramètres divers et variés, des menus contextuels, des frames, etc. sont des pistes qui peuvent être explorées. Et l'expérience se gagne essentiellement par la pratique.