Développez avec des logiciels libres sur la Freebox !

Magazine
Marque
GNU/Linux Magazine
HS n°
Numéro
51
Mois de parution
décembre 2010
Spécialité(s)


Résumé
Depuis maintenant un peu moins d'un an, Free offre la possibilité d'exécuter sur la Freebox des applications écrites en JavaScript utilisant les Enlightenment Foundation Libraries pour réaliser l'interface graphique.

Body

1. Enlightenment et les EFL

Les EFL, Enlightenment Foundation Libraries, sont les bases d'un toolkit développé par l'équipe du projet Enlightenment depuis un peu plus de 10 ans, principalement pour le gestionnaire de fenêtres E17. Le projet E17 visant à fournir un gestionnaire de fenêtres à la fois joli, léger et rapide a donc mis de très gros efforts dans la réalisation d'une base saine, légère et rapide. Les EFL ont évolué dans le temps et sont maintenant destinées à la réalisation de tout type d'application ; à tel point qu'aujourd'hui, l'objectif est d'en faire un concurrent dans l'embarqué face aux poids lourds tels que QT ou GTK.

C'est ainsi que les EFL viennent de passer en version Alpha, ce qui garantira une compatibilité API/ABI la plus longue possible dans le temps. La version 1.0 devrait être disponible d'ici peu, et l'objectif est que la version 2.0 (permettant éventuellement de « casser » l'ABI) ne sorte pas avant plusieurs années. Avec cette sortie, les EFL entrent définitivement dans la cour des grands et cassent un peu plus ce mythe de vaporware. D'ailleurs, pour le clin d'œil, Free a inclus Duke Nukem 3D dans le même firmware mettant à disposition Elixir, ce framework JavaScript qui utilise les EFL.

Les EFL ont été découpées en morceaux logiques pour en faciliter la compréhension et la maintenance :

Eina est la base de toutes les EFL. Une bibliothèque de types de données qui essayent de rendre le plus simple possible la manipulation efficace de ces types. Dans le cadre du projet Elixir et sur la Freebox, celle-ci n'est pas du tout exposée aux utilisateurs car le JavaScript a déjà, contrairement au C, ces fonctionnalités dans le langage.

Eet fournit une mécanique robuste et efficace pour sérialiser et enregistrer des données dans un fichier ou les envoyer sur le réseau. Cela inclut n'importe quelle structure mémoire, des images ou encore les scripts JavaScript d'Elixir.

Evas est un canvas graphique stateful. C'est réellement le cœur des EFL car c'est Evas qui est en charge de la gestion et de l'affichage des objets sur le canvas graphique. C'est cette bibliothèque qui optimise toutes les requêtes au système graphique pour tirer au mieux parti des performances du matériel.

Ecore est chargé de gérer tous les événements, qu'ils soient liés aux fenêtres graphiques (redimensionnement, déplacement, ...) ou au réseau.

Edje permet quant à elle de définir indépendamment du code de l'application son look & feel. Cela permet, par exemple, d'aussi bien définir le layout des menus d'une application que les animations d'un sprite. L'intérêt étant de pouvoir avoir plusieurs versions d'un thème s'adaptant le mieux possible au terminal cible, une véritable abstraction entre le code et l'interface

Sur ces bases vient se poser Elixir, qui expose directement l'API C des EFL en JavaScript grâce à la bibliothèque SpiderMonkey du projet Mozilla. Ce qui fait de cette solution un framework entièrement libre et ouvert, portable et intégrable facilement sur des plates-formes même très limitées. Pour pouvoir bénéficier d'un maximum d'exemples, de documentation et d'aide, il a été préféré de ne pas faire une API orientée objet : cela permet de réutiliser quasi directement les exemples en C.

2. Elixir

Il existe plusieurs manières de récupérer les EFL et SpiderMonkey. Ainsi, il existe un PPA pour Ubuntu, de Cédric Schieli, ppa:cschieli/freebox-elixir, des paquets sont aussi disponibles dans AUR pour Arch et il est bien entendu possible de tout compiler à la main en partant des sources. Pour ce dernier cas, nous vous laisserons consulter la documentation disponible sur http://code.google.com/p/freebox-elixir/wiki/InstallerElixir. Free met aussi à disposition une image pour machine virtuelle VirtualBox à l'adresse : ftp://ftp.free.fr/pub/elixir/Elixir_virtualbox.tar.gz. Ceci doit permettre de démarrer à développer sans trop perdre de temps sur des détails de compilation et d'installation.

Essayons donc, pour commencer, de réaliser un classique Hello World!. Tout d'abord, il faut charger les bindings nécessaires à notre exemple, c'est-à-dire Evas, Ecore et Ecore_Evas. Chaque module pouvant exister de manière optionnelle, il est considéré comme étant une bonne pratique de vérifier la valeur de retour de la fonction elx.load.

var test = true;

test &= elx.load("evas");

test &= elx.load("ecore");

test &= elx.load("ecore-evas");

Maintenant que les bindings sont activés, il faut initialiser les EFL, créer une fenêtre, ajouter le texte au canvas, puis enfin, attendre que l'utilisateur presse sur une touche avant de quitter. Il va donc falloir utiliser Ecore puis Evas. Regardons ce que cela donne :

  var background;

  var obj;

  ecore_init();

  ecore_evas_init();

// Création de la fenêtre

  var ee = ecore_evas_new(null, 0, 0, 720, 576, "name=Hello World;");

// Obtention du canvas lié à la fenêtre

  var evas = ecore_evas_get(ee);

// Définition des contraintes sur le canvas

  evas_image_cache_set(evas, 10 * 1024 * 1024);

evas_font_path_prepend(evas, "/.fonts/");

  evas_font_cache_set(evas, 512 * 1024);

  // Création d'un background noir opaque

  obj = evas_object_rectangle_add(evas);

  evas_object_resize(obj, 720, 576);

  evas_object_color_set(obj, 0, 0, 0, 255);

  evas_object_show(obj);

background = obj;

  // Création de l'objet texte

  obj = evas_object_text_add(evas);

  evas_object_text_text_set(obj, "Hello World!");

  evas_object_text_font_set(obj, "Vera", 30);

  evas_object_text_style_set(obj, EVAS_TEXT_STYLE_SOFT_SHADOW);

  evas_object_text_shadow_color_set(obj, 128, 128, 128, 255);

  evas_object_color_set(obj, 128, 64, 0, 180);

  evas_object_resize(obj, 200, 50);

  evas_object_move(obj, 100, 100);

  evas_object_show(obj);

Comme Evas est un canvas stateful, nous créons les objets qui seront affichés à l'écran, puis on en change les propriétés pour obtenir le résultat voulu. Par contre, vous noterez la présence d'un rectangle noir explicitement défini pour le fond. Il est nécessaire, car Evas n'a pas de notion d'initialisation du fond d'écran avec une valeur quelconque. Donc, sans cet objet, Evas ne saurait pas quoi mettre comme contenu dans les pixels composant le fond. Vous pouvez tester en désactivant juste l'appel à evas_object_show, qui correspond au fond d'écran (par défaut, les objets ne sont pas visibles). Ce bout de code a aussi introduit deux types d'objets gérés par Evas : les rectangles et le texte. Evas gère aussi des images, des blocs de texte, des tables, des listes fixes (appelées box) et des objets composés de toutes ces primitives (appelés smart objects).

Ajoutons maintenant la gestion du clavier pour quitter l'application :

   evas_object_event_callback_add(background, EVAS_CALLBACK_KEY_UP, key_up_cb, null);

   evas_object_focus_set(background, 1);

   ecore_evas_show(ee);

ecore_main_loop_begin();

Voilà ! Nous avons maintenant attaché une callback sur l'objet background et défini qu'il recevrait les événements clavier puisqu'il possède le focus (evas_object_focus_set). Enfin, la fenêtre a été affichée juste avant de démarrer la boucle principale du programme. C'est cette boucle qui déclenchera au moment opportun la mise à jour du rendu à l'écran et transmettra les événements clavier à Evas sans bloquer l'interactivité de l'application. Détaillons donc le contenu de la fonction key_up_cb :

function key_up_cb(data, e, obj, event)

{

   switch (event.keyname)

     {

      case "b":

      case "Red":

      case "equal":

      case "Stop":

      case "Home":

      case "Escape":

      case "Start":

         ecore_main_loop_quit();

break;

     }

}

On notera qu'ici, le langage JavaScript nous aide en permettant de directement faire un switch sur des chaînes de caractères, ce qui simplifie grandement le code. On précisera que ecore_main_loop_quit va demander à ecore de quitter la boucle principale, mais ne quittera pas brutalement le programme. On va donc revenir à la fonction d'initialisation, juste après l'appel à ecore_main_loop_begin, et on en profitera pour tout désinitialiser proprement en détruisant les objets du canvas ainsi que la fenêtre et en « coupant » les EFL utilisées dans l'exemple.

  evas_object_del(obj);

  evas_object_del(background);

  ecore_evas_free(ee);

  ecore_evas_shutdown();

ecore_shutdown();

Voici donc un exemple simple mais peu animé (ou plutôt très statique !). Nous allons maintenant ajouter du tonus à ce texte en le faisant rebondir d'un bout à l'autre de l'écran. Pour cela, nous allons utiliser un timer un peu spécial : un animator. Utiliser un timer classique dans cet exemple ne comportant une seule animation n'aurait pas vraiment montré de problème, mais lorsqu'on a beaucoup d'objets en mouvement, on veut que leurs déplacements soient synchronisés. Pour cela, il faut synchroniser les timers entre eux, ce qui n'est pas vraiment pratique. C'est ainsi que l'on fait appel à un type spécial de timers, qui vont toujours s'exécuter ensemble au même rythme, et ainsi, permettre à l'animation d'une frame d'être toujours complète. Commençons donc par l'initialiser juste après avoir créé le texte :

   obj.dx = +20;

   obj.dy = +10;

   obj.x = 100;

   obj.y = 100;

   obj.w = 200;

obj.h = 50;

   obj.constrain = { x: 0, y: 0, w: 720, h: 576 };

   ecore_animator_add(anim_cb, obj);

La première chose que l'on remarque ici, c'est que nous définissons des propriétés supplémentaires à l'objet texte. Le problème que l'on tente de résoudre par cette démarche est que faire des allers-retours entre le monde en C et le JavaScript est coûteux. Pour éviter ceci, on utilise aussi longtemps que possible les informations connues par le JavaScript, puis on copie la dimension de l'objet texte et on lui ajoute également une propriété de vitesse, dx et dy. Avec cela, on est prêt à lancer l'animation, il ne reste plus qu'à coder anim_cb.

function anim_cb(obj)

{

   var x;

   var y;

   x = obj.x + obj.dx;

   y = obj.y + obj.dy;

   if (x + obj.w > obj.constrain.x + obj.constrain.w || x < obj.constrain.x)

     {

        obj.dx = - obj.dx;

        x += 2 * obj.dx;

     }

   if (y + obj.h > obj.constrain.y + obj.constrain.h || y < obj.constrain.y)

     {

        obj.dy = - obj.dy;

        y += 2 * obj.dy;

     }

   evas_object_move(obj, x, y);

obj.x = x;

   obj.y = y;

   return true;

}

Le code de l'animation est plutôt simple : on déplace l'objet à la vitesse dx/dy en gérant juste un rebond/changement de direction lorsqu'on atteint un des bords de l'écran. Vous pouvez assez facilement ajouter d'autres objets et (par exemple) changer la couleur avec evas_object_color_set.

Avec cet exemple, vous avez vu comment fonctionne un canvas stateful et comment on peut réaliser des animations. C'est la base de toute interface, mais cela deviendra vite laborieux de devoir déclarer chaque objet à la main dans le JavaScript. Cela ne permet pas non plus de séparer le design du code et ralentit l'adaptation de l'interface aux plates-formes cibles. C'est pour cela que le projet Enlightenment a développé la technologie Edje qui est là pour adresser tous ces problèmes. Edje mériterait bien plus qu'un article, mais pour cette fois-ci, nous allons juste l'utiliser pour changer le rectangle du fond d'écran et en faire un layout simple. Avant d'utiliser Edje, il ne faut pas oublier de charger son binding à l'aide d'un elx.load("edje"). Ensuite, nous allons créer un fichier elixir.edc qui va contenir notre layout :

collections {

   group {

      name: "main";

      parts {

         part {

            name: "background";

            type: RECT;

            mouse_events: 0;

            description {

               state: "default" 0.0;

               rel1.relative: 0.0 0.0;

               rel2.relative: 1.0 1.0;

               color: 0 0 100 255;

}

         }

      }

   }

}

Le principe d'un fichier Edje est de décrire différents groupes d'objets qui pourront s'instancier dans un unique objet Edje dans le JavaScript. Ici, on ne crée qu'un seul groupe, ne contenant qu'un seul objet, background, qui prend toute la surface de l'objet Edje et aura du bleu foncé comme couleur. Il est à noter qu'il est préférable d'exprimer les coordonnées d'un objet de manière relative dans un fichier Edje. Maintenant que nous avons notre fichier de descriptions, il faut le compiler dans sa forme finale grâce à la commande edje_cc -v elixir.edc elixir.edj. À partir de ce fichier Edje, nous pouvons instancier un objet Edje pour le fond d'écran en remplaçant les appels à evas_object_rectangle_add et evas_object_color_set par :

   obj = edje_object_add(evas);

   edje_object_file_set(obj, "elixir.edj", "main");

Et voilà un superbe fond bleu ! Nous pouvons un peu amélioré ceci en limitant la zone d'animation avec un deuxième rectangle, un peu à la manière d'une zone de jeu. Pour cela, ajoutons une deuxième part à notre fichier Edje :

         part {

            name: "constrain";

            type: RECT;

            mouse_events: 0;

            description {

               state: "default" 0.0;

               rel1.relative: 0.1 0.1;

               rel2.relative: 0.7 0.9;

               color: 0 0 180 255;

}

         }

Il reste à prendre en compte les caractéristiques de cet objet dans notre JavaScript en changeant juste la ligne obj.constrain = { x: 0, y: 0, w: 720, h: 576 } par obj.constrain = edje_object_part_geometry_get(background, "constrain"). Après recompilation du fichier Edje, l'animation se fait maintenant dans un cadre plus limité. On peut facilement modifier les coordonnées de cette zone et voir les résultats du JavaScript varier. Mais il y a quand même un défaut : le point de départ du texte n'est pas forcément dans la zone d'animation, ce qui peut provoquer de petits inconvénients. Pour cela, une légère modification résoudra le problème :

   obj.x = obj.constrain.x + 10;

   obj.y = obj.constrain.y + 10;

   evas_object_move(obj, obj.x, obj.y);

Il reste une dernière notion à aborder dans Edje : les animations. Dans les objets que nous avons décrits jusqu'à présent, nous n'avons spécifié qu'une description par défaut, qui est l'état initial d'une part lors du chargement d'un Edje. En en créant plusieurs, nous pouvons définir les bases d'une animation :

         part {

            name: "animation";

            type: RECT;

            mouse_events: 0;

            description {

               state: "default" 0.0;

               rel1.relative: 0.75 0.1;

               rel2.relative: 0.85 0.2;

               color: 0 0 255 255;

            }

            description {

               state: "right" 0.0;

               rel1.relative: 0.85 0.1;

               rel2.relative: 0.95 0.2;

               color: 255 0 0 255;

            }

            description {

               state: "bottom" 0.0;

               rel1.relative: 0.75 0.8;

               rel2.relative: 0.85 0.9;

               color: 0 255 0 255;

}

         }

Il faut maintenant décrire la logique de l'animation grâce à une série de programmes qui seront déclenchés lors de l'affichage de l'objet après une période d'attente aléatoire :

      programs {

         program {

            name: "beginning";

            source: "";

            signal: "show";

            in: 0.1 1.0;

            action: STATE_SET "right" 0.0;

            transition: LINEAR 0.5;

            target: "animation";

            after: "nextstep";

         }

         program {

            name: "nextstep";

            action: STATE_SET "bottom" 0.0;

            transition: SINUSOIDAL 0.8;

            target: "animation";

            after: "laststep";

         }

         program {

            name: "laststep";

            action: STATE_SET "default" 0.0;

            transition: ACCELERATE 0.8;

            target: "animation";

            after: "beginning";

}

      }

Le premier programme (beginning) démarrera lorsqu'il recevra le signal show après un temps d'attente entre 0,1 et 1,1 seconde. show est un signal envoyé automatiquement par Edje dès l'affichage de la première frame, mais il est possible d'envoyer des signaux depuis le JavaScript avec edje_object_signal_emit, ce qui permet d'intégrer complètement l'Edje au JavaScript. Nous allons donc ajouter une part dont l'animation sera contrôlée directement par le JavaScript et qui changera d'état entre visible et invisible en fonction de l'appui sur une touche du clavier.

         program {

            source: "js";

            signal: "toggle";

            filter: "feedback" "default";

            action: STATE_SET "transparent" 0.0;

            transition: LINEAR 0.5;

            target: "feedback";

            after: "back";

         }

         program {

            source: "js";

            signal: "toggle";

            filter: "feedback" "transparent";

            action: STATE_SET "default" 0.0;

            transition: LINEAR 0.5;

            target: "feedback";

            after: "back";

         }

         program {

            name: "back";

            action: SIGNAL_EMIT "toggle" "end";

}

On utilise ici deux nouvelles possibilités de Edje. Tout d'abord, chaque programme interceptant les signaux ne sera déclenché que si la part feedback est dans l'état spécifié dans le second paramètre. Cela évite de devoir coder tous les états possibles dans le JavaScript et permet d'ajouter facilement de nouveaux états intermédiaires. Enfin, pour permettre des animations de temps variable, il faut notifier au JavaScript quand elles se terminent. C'est à cela que sert le SIGNAL_EMIT. Les signaux envoyés par Edje peuvent être captés de manière identique dans un programme et en JavaScript. Pour cela, il suffit d'enregistrer une callback pour un signal particulier à la création de l'objet Edje : edje_object_signal_callback_add(obj, "toggle", "end", toggle_end_cb, null) dans notre exemple. La fonction gérant le signal va être très simple dans notre cas :

function toggle_end_cb(data, obj, emission, source)

{

   obj.toggling = false;

}

Il manque juste un petit morceau de code pour envoyer le signal depuis le JavaScript dans le handler de clavier :

      case "x":

         if (!obj.toggling)

           {

              edje_object_signal_emit(obj, "toggle", "js");

              obj.toggling = true;

}

         break;

Et voilà, ça fonctionne ! Rien de bien compliqué pour un exemple qui commence à bouger. Il y a encore beaucoup d'autres fonctionnalités à voir dans Edje ; on peut toutes les retrouver dans la documentation à l'adresse http://docs.enlightenment.org/auto/edje/edcref.html. Notre première application est presque finie, il ne reste plus qu'à en faire un seul fichier pour être déployé plus facilement. Pour cela, nous nous appuyons sur le format de fichier de Edje qui utilise Eet et qui peut intégrer plusieurs sections différentes et indépendantes. Vous pouvez voir les sections composant un fichier Edje de la manière suivante :

$ eet -l elixir.edj

edje_source_fontmap

edje_sources

edje/file

edje/collections/0

$

Nous allons donc simplement insérer le fichier JavaScript dans une section utilisée par Elixir à l'aide de la commande eet -i elixir.edj elixir/main elixir.js. Il suffit maintenant d'exécuter elixir elixir.edj ou de déposer le fichier sur le disque dur de la Freebox via son serveur FTP, ou encore de l'envoyer via http://factory.free.fr sur le Freestore. Bien entendu, tout ce code d'exemple et bien plus sont disponibles à l'adresse : http://code.google.com/p/freebox-elixir/source/browse/#svn/trunk/exemples/articles/introduction.




Article rédigé par

Par le(s) même(s) auteur(s)

Application native moderne en Go : manipulation de données, tests unitaires, intégration et GitHub

Magazine
Marque
GNU/Linux Magazine
Numéro
263
Mois de parution
mai 2023
Spécialité(s)
Résumé

Il est temps d’aussi utiliser des outils modernes quand on développe des applications natives multiplateformes ! Dans notre dernier article, nous avons mis en place notre environnement de développement et créé notre première application multiplateforme en utilisant l'idée d’une gestion de liste de courses. Mais celle-ci était assez limitée. Elle n’avait pas les moyens de sauvegarder ses données et d’exporter ou d’importer des listes. On n’a pas non plus tiré pleinement bénéfice de l'écosystème Go...

Application native moderne en Go

Magazine
Marque
GNU/Linux Magazine
Numéro
262
Mois de parution
mars 2023
Spécialité(s)
Résumé

Il est temps d’utiliser aussi des outils modernes quand on développe des applications natives multiplateformes ! Nous vivons une époque très intéressante avec une vague de langages de développement qui tente d’offrir des solutions modernes permettant de produire du code plus performant plus efficacement, avec moins de bugs et en couvrant une plus grande diversité d’utilisateurs.

Les derniers articles Premiums

Les derniers articles Premium

Quarkus : applications Java pour conteneurs

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Initié par Red Hat, il y a quelques années le projet Quarkus a pris son envol et en est désormais à sa troisième version majeure. Il propose un cadre d’exécution pour une application de Java radicalement différente, où son exécution ultra optimisée en fait un parfait candidat pour le déploiement sur des conteneurs tels que ceux de Docker ou Podman. Quarkus va même encore plus loin, en permettant de transformer l’application Java en un exécutable natif ! Voici une rapide introduction, par la pratique, à cet incroyable framework, qui nous offrira l’opportunité d’illustrer également sa facilité de prise en main.

De la scytale au bit quantique : l’avenir de la cryptographie

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Imaginez un monde où nos données seraient aussi insaisissables que le célèbre chat de Schrödinger : à la fois sécurisées et non sécurisées jusqu'à ce qu'un cryptographe quantique décide d’y jeter un œil. Cet article nous emmène dans les méandres de la cryptographie quantique, où la physique quantique n'est pas seulement une affaire de laboratoires, mais la clé d'un futur numérique très sécurisé. Entre principes quantiques mystérieux, défis techniques, et applications pratiques, nous allons découvrir comment cette technologie s'apprête à encoder nos données dans une dimension où même les meilleurs cryptographes n’y pourraient rien faire.

Les nouvelles menaces liées à l’intelligence artificielle

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Sommes-nous proches de la singularité technologique ? Peu probable. Même si l’intelligence artificielle a fait un bond ces dernières années (elle est étudiée depuis des dizaines d’années), nous sommes loin d’en perdre le contrôle. Et pourtant, une partie de l’utilisation de l’intelligence artificielle échappe aux analystes. Eh oui ! Comme tout système, elle est utilisée par des acteurs malveillants essayant d’en tirer profit pécuniairement. Cet article met en exergue quelques-unes des applications de l’intelligence artificielle par des acteurs malveillants et décrit succinctement comment parer à leurs attaques.

Les listes de lecture

9 article(s) - ajoutée le 01/07/2020
Vous désirez apprendre le langage Python, mais ne savez pas trop par où commencer ? Cette liste de lecture vous permettra de faire vos premiers pas en découvrant l'écosystème de Python et en écrivant de petits scripts.
11 article(s) - ajoutée le 01/07/2020
La base de tout programme effectuant une tâche un tant soit peu complexe est un algorithme, une méthode permettant de manipuler des données pour obtenir un résultat attendu. Dans cette liste, vous pourrez découvrir quelques spécimens d'algorithmes.
10 article(s) - ajoutée le 01/07/2020
À quoi bon se targuer de posséder des pétaoctets de données si l'on est incapable d'analyser ces dernières ? Cette liste vous aidera à "faire parler" vos données.
Voir les 64 listes de lecture

Abonnez-vous maintenant

et profitez de tous les contenus en illimité

Je découvre les offres

Déjà abonné ? Connectez-vous