Fedora-Fr - Communauté francophone Fedora - Linux

Planet de Fedora-Fr : la communauté francophone autour de la distribution Linux Fedora

A propos

Cette page est actualisée toutes les heures.

Cette page est une sélection de blogs autour de Fedora. Fedora-Fr.org décline toute responsabilité au sujet des propos tenus par les auteurs des blogs de ce planet. Leurs propos sont leur entière responsabilité.

Le contenu de ce planet appartient à leurs auteurs respectifs. Merci de consulter leur blogs pour obtenir les licences respectives.

Fedora 15 alpha

Carlos Vassalo La version alpha de Fedora 15 est disponible. Même si, habituellement, les versions alpha sont déjà relativement stables, n’oubliez pas qu’il s’agit d’une version de développement. Et comme toutes versions de développement, elle est là pour être testée massivement, pour dénicher et corriger un maximum d’erreurs. On ne le dira jamais assez : la télécharger [...]

Où en suis-je ?

Alexandre Frandemiche

Bonjour à tous !

Ce blog est peu actif de manière général, je n'ai pas de temps, entre la direction de Muffin, la gestion du serveur Communauté-SLA.org, la rédaction et gestion de Paquets Fedora du Jour, la gestion du projet politique EcoHumanismeRadical, mon travail au sein d'Opti-Time (qui me permet de voir beaucoup de chose dans le domaine du libre) et enfin une vie personnelle (et oui, j'en ai une !!!), je vois de plus en plus le temps pour chacun se réduire !

direction?Pas facile de gérer ... surtout qu'en fond, j'ai aussi des envies en terme de domotique, à réaliser, du coup je manque aussi de temps pour avancer dans ce projet. D'ailleurs au passage pour ceux que ça intéresse, j'ai migrer mon NAS ReadyNas Duo vers un ReadyNas Ultra 4 en Novembre dernier, je crois ! Mais ça sera l'objet d'un prochain billet ! (Tonido, transmission, Weave Server, ect sont autant d'installation que j'aimerai publier sur ce blog).

Bref, entre la mise en place d'un serveur Nagios, d'un portail communautaire (avec accueil, forum (fluxBB), planet (BilboPlanet), chat (JappixMini), plateforme de blog (Dotclear) et wiki (Dokuwiki)), des éléments d'administration (phpMyAdmin, phpMyBackup, phpPgAdmin), de la gestion de serveurs virtuels (ESXi, Xen, VirtualBox), outils divers (TikiWiki, OpenFire, Papillon), des outils de compilations (Maven, Continuum, Saunar). Des création de rpm que j'aimerai diffuser (rpm de tomcat multiple basé sur le tomcat de yum, rpm de plugin eclipse, pour des plugin nagios, talend, birt, ect ...).

J'ai aussi des envies de partager et de communiquer sur un ETL open source Talend, sur lequel j'ai été formé récemment ...
Et dans tout ça, j'en oublie très certainement ...

Mine de rien, je pense qu'avec 3 mois de retard je viens de réaliser une sorte de billet "Bonnes résolutions 2011" ! :) !

Je vais commencer par fournir une procédure d'installation de Nagios 3.X sous Fedora et CentOS. Je vais rédiger ce billet aujourd'hui, on verra quand je le publierai réellement ;) !

Alors à bientôt et j'espère réaliser plus de billets rendez-vous dans quelques temps afin de voir ce que j'ai réalisé ... ou pas !

Quand JPackage n'autorise pas l'installation de tomcat6 sous CentOS 5 ...

Alexandre Frandemiche

Ce billet à pour but de ne pas oublier cette petite manipulation concernant l'installation d'un Tomcat 6 sous centOS 5 :

Ajout du dépôt JPackage :

su -
cd /etc/yum.repos.d/
wget http://www.jpackage.org/jpackage50.repo

Installation de Tomcat 6 :

yum install tomcat6

On obtient l'erreur suivante :

Loaded plugins: downloadonly, fastestmirror
Loading mirror speeds from cached hostfile
* epel: fr2.rpmfind.net
* jpackage-generic: mirror.ibcp.fr
* base: centos.crazyfrogs.org
* updates: centos.crazyfrogs.org
* jpackage-generic-updates: mirror.ibcp.fr
* extras: centos.crazyfrogs.org
* addons: centos.crazyfrogs.org
Setting up Install Process
Parsing package install arguments
Resolving Dependencies
--> Running transaction check
---> Package tomcat6.noarch 0:6.0.29-1.jpp5 set to be updated
--> Processing Dependency: tomcat6-lib = 6.0.29-1.jpp5 for package: tomcat6
--> Processing Dependency: java for package: tomcat6
--> Processing Dependency: jakarta-commons-logging for package: tomcat6
--> Processing Dependency: jakarta-commons-daemon for package: tomcat6
--> Running transaction check
---> Package java-1.6.0-openjdk.i386 1:1.6.0.0-1.16.b17.el5 set to be updated
--> Processing Dependency: libgif.so.4 for package: java-1.6.0-openjdk
--> Processing Dependency: tzdata-java for package: java-1.6.0-openjdk
---> Package tomcat6-lib.noarch 0:6.0.29-1.jpp5 set to be updated
--> Processing Dependency: tomcat6-el-1.0-api = 6.0.29-1.jpp5 for package: tomcat6-lib
--> Processing Dependency: tomcat6-jsp-2.1-api = 6.0.29-1.jpp5 for package: tomcat6-lib
--> Processing Dependency: tomcat6-servlet-2.5-api = 6.0.29-1.jpp5 for package: tomcat6-lib
--> Processing Dependency: ecj for package: tomcat6-lib
--> Processing Dependency: /usr/share/java/ecj.jar for package: tomcat6-lib
--> Processing Dependency: jakarta-commons-dbcp-tomcat5 for package: tomcat6-lib
--> Processing Dependency: jakarta-commons-collections-tomcat5 for package: tomcat6-lib
--> Processing Dependency: jakarta-commons-pool-tomcat5 for package: tomcat6-lib
---> Package jakarta-commons-daemon.i386 1:1.0.1-6jpp.1 set to be updated
--> Processing Dependency: java-gcj-compat for package: jakarta-commons-daemon
--> Processing Dependency: libgcj_bc.so.1 for package: jakarta-commons-daemon
---> Package jakarta-commons-logging.i386 0:1.0.4-6jpp.1 set to be updated
--> Running transaction check
---> Package tzdata-java.i386 0:2010l-1.el5 set to be updated
---> Package tomcat6-servlet-2.5-api.noarch 0:6.0.29-1.jpp5 set to be updated
---> Package jakarta-commons-dbcp-tomcat5.noarch 0:1.2.2-2.jpp5 set to be updated
---> Package ecj.noarch 1:3.3.1.1-3.jpp5 set to be updated
---> Package jakarta-commons-pool-tomcat5.noarch 0:1.3-11.jpp5 set to be updated
---> Package java-1.4.2-gcj-compat.i386 0:1.4.2.0-40jpp.115 set to be updated
--> Processing Dependency: /usr/bin/rebuild-security-providers for package: java-1.4.2-gcj-compat
--> Processing Dependency: /usr/bin/rebuild-security-providers for package: java-1.4.2-gcj-compat
--> Processing Dependency: gjdoc for package: java-1.4.2-gcj-compat
---> Package libgcj.i386 0:4.1.2-48.el5 set to be updated
---> Package tomcat6-el-1.0-api.noarch 0:6.0.29-1.jpp5 set to be updated
---> Package jakarta-commons-collections-tomcat5.i386 0:3.2-2jpp.3 set to be updated
---> Package tomcat6-jsp-2.1-api.noarch 0:6.0.29-1.jpp5 set to be updated
---> Package eclipse-ecj.i386 1:3.2.1-19.el5.centos set to be updated
---> Package giflib.i386 0:4.1.3-7.1.el5_3.1 set to be updated
--> Running transaction check
---> Package java-1.4.2-gcj-compat.i386 0:1.4.2.0-40jpp.115 set to be updated
--> Processing Dependency: /usr/bin/rebuild-security-providers for package: java-1.4.2-gcj-compat
--> Processing Dependency: /usr/bin/rebuild-security-providers for package: java-1.4.2-gcj-compat
---> Package gjdoc.i386 0:0.7.7-12.el5 set to be updated
--> Processing Dependency: antlr for package: gjdoc
--> Running transaction check
---> Package java-1.4.2-gcj-compat.i386 0:1.4.2.0-40jpp.115 set to be updated
--> Processing Dependency: /usr/bin/rebuild-security-providers for package: java-1.4.2-gcj-compat
--> Processing Dependency: /usr/bin/rebuild-security-providers for package: java-1.4.2-gcj-compat
---> Package antlr.i386 0:2.7.6-4jpp.2 set to be updated
--> Finished Dependency Resolution java-1.4.2-gcj-compat-1.4.2.0-40jpp.115.i386 from base has depsolving problems
--> Missing Dependency: /usr/bin/rebuild-security-providers is needed by package java-1.4.2-gcj-compat-1.4.2.0-40jpp.115.i386 (base)
Error: Missing Dependency: /usr/bin/rebuild-security-providers is needed by package java-1.4.2-gcj-compat-1.4.2.0-40jpp.115.i386 (base)

Résolution de l'installation :
yum remove jpackage-utils
yum --disablerepo=jpackage* install jpackage-utils
yum install tomcat6

Et voilà, plus derreur, visiblement le paquet jpackage-utils de Jpackage ne fonctionne pas, donc on utilise celui des dépôts CentOS !

Fedora | Toulouse ?

Pierre-Yves Chibon

French version (no english, sorry)

Bonsoir à tous,

Récemment, j'ai constaté que l'on a quelques toulousain sur le forum et je me suis dit "Tiens se serai sympa de se retrouver" (oui je suis comme ça moi...).

Et bien je profite de mon passage à Toulouse le week-end prochain pour lancer le mouvement :-)

Donc, Amies Toulousaines, Amis Toulousains :

  • Rendez-vous Samedi 12 mars (et non 19, je serais pas là)
  • Au Café de Toulouse
  • À 17h30

Hésitez pas à annoncer votre venue ici ;-)

Catpure vidéo écran screencast sous Fedora avec ffmpeg

Patrice Ferlet

La capture vidéo d'écran est un sujet maintes fois soulevé sous Linux et il existe de jolis services fais pour ça. Mais quand ça ne marche pas on a du mal à trouver des solutions simples... Istanbul, gtk-recordMyDesktop, je les ai essayé... mais à chaque fois un souci apparait, soit avec le son, soit avec la vidéo. Alors pourquoi ne pas passer par la ligne de commande ? ffmpeg est juste parfait ! alors on se lance. Encore une fois, si je trouve pas ce qui me plait, je le code :)" class="smiley donc vous aurez un script en bas de billet qui fait tout ça.

En premier lieu, le but est d'avoir: une vidéo de bonne qualité, capture du son depuis un micro, et un contrôle possible de la zone à sauver. Bref, il nous faut chercher tout ça dans les documentations. Comme je suis gentil, je vous donne au fur et à mesure la méthode, et même un petit script qui va vous aider.

Permière tâche à effecturer: capturer l'écran. ffmpeg à un format d'entré nommé "x11grab". Ce format d'entrée permet d'utiliser un port X de capture. Dans la majeur partie des cas on utilise "0.0"

Il faut par contre définir une taille obligatoirement, mon écran est de résoltion 1366x768. On trouve facilement la configuration de cette manière:

xrandr
creen 0: minimum 320 x 200, current 1366 x 768, maximum 1600 x 1600
LVDS connected 1366x768+0+0 (normal left inverted right x axis y axis) 344mm x 193mm
   1366x768       60.0*+
   1360x768       60.0  
   1280x768       60.0  
   1280x720       60.0  
   1024x768       60.0  
   1024x600       60.0  
   800x600        60.0  
   800x480        60.0  
   640x480        60.0  
DFP1 disconnected (normal left inverted right x axis y axis)
CRT1 disconnected (normal left inverted right x axis y axis)

Il faut aussi spécifier la fréquence de frame par seconde, 15 est un minimum, mais 25 ou 30 images par seconde est plus fluide. Bref...

Donc, pour capturer l'écran:

ffmpeg -f x11grab -i 0.0 -s 1366x768 -r 25 -y /tmp/out.avi

Cela fonctionne bien, en pressant "q" dans la console on coupe la capture, voyez ensuite la vidéo:

ffplay /tmp/out.avi

Niveau qualité... moyen... on ajoute alors un débit de lecture pour s'assurer d'un bon rendu. Personnellement j'ai trouvé que 7000kb/s est pas mal du tout:

ffmpeg -f x11grab -i 0.0 -s 1366x768 -r 25 -b 7000k -y /tmp/out.avi

Voilà. Pour le moment on a bien une manière de capturer la vidéo. Reste à capturer du son. ffmpeg sait très bien capturer le son depuis votre interface alsa.

Tout le problème est de savoir quel est l'identifiant alsa à capturer... personnellement j'ai une webcam avec micro, une carte hdmi qui peut sortir du son et une interface interne pour sortir du son sur mes enceintes... bref, 3 cartes...

L'investigation est en fait très simple, Linux a cet avantage de tout faire dans des fichiers ou pseudo fichiers. Nos cartes sons sont en fait interrogeables depuis /proc/asound qui nous donne un paquet d'informations.

Regardons:

D'abords je cherche ma webcam... ne vous fiez pas au nom complètement batard que vous allez voir, c'est juste que cette webcam envoit un nom bien affreux. Dans les autres cas vous verrez certainement des choses plus lisibles.

cat /proc/asound/cards
 0 [U0x46d0x825    ]: USB-Audio - USB Device 0x46d:0x825
                      USB Device 0x46d:0x825 at usb-0000:00:1d.0-1.2, high speed
 1 [Intel          ]: HDA-Intel - HDA Intel
                      HDA Intel at 0xb4100000 irq 44
 2 [Generic        ]: HDA-Intel - HD-Audio Generic
                      HD-Audio Generic at 0xb4020000 irq 45

donc ici on voit mes 3 cartes, La Intel, la Generic et ma webcam avec ce fameux nom "U0x46d0x825". Ce qui nous intéresse ici c'est surtout l'index, le permier chiffre qui apparait sur la première colone. Ma webcam (ou du moins son interface de son) est "0". Cela va vouloir dire que nous utiliserons ce chiffre pour définir la carte à utiliser.

Attention, un carte peut avoir plusieurs interfaces de capture, par exemple une entrée "line in" et "mic"... il faut donc trouver quel est l'interface qui nous convient. Cela se passe dans un second fichier:

cat /proc/asound/devices 
  2:        : timer
  3:        : sequencer
  4: [ 1- 0]: digital audio playback
  5: [ 1- 0]: digital audio capture
  6: [ 1- 0]: hardware dependent
  7: [ 1]   : control
  8: [ 2- 3]: digital audio playback
  9: [ 2- 0]: hardware dependent
 10: [ 2]   : control
 11: [ 0- 0]: digital audio capture
 12: [ 0]   : control

Ce qui est intéressant ici, c'est la seconde colonne, elle spécifie l'index de la carte suivi de l'index d'interface. Dans notre cas, pour ma webcam, je cherche l'index 0, c'est à dire les ligne préfixées par 11 et 12. On voit que l'interface 0-0 est une entré de capture de son... parfait !

La notation alsa est simple: "hw:" suivit de l'index, une virgule, le numéro d'interface. Ma webcam est représentée par "hw:0,0"

ainsi, ffmpeg me permet d'enregistrer du son depuis mon micro de cette manière:

ffmpeg -f alsa -i hw:0,0 -y /tmp/out.ogg

Et de ce fait, /tmp/out.ogg est un fichier son qui a enregistré ma voix depuis ma webcam. Bon, et bien allons y maintenant, on va utiliser les deux flux (vidéo et audio) et on les envoit dans un fichier:

ffmpeg -f x11grab -i 0.0 -s 1366x768 -r 25 -b 7000k -f alsa -i hw:0,0 -y /tmp/out.avi

Evidamment, vous pouvez utiliser d'autres formats de sortie, comme le webm, libx264, ogv, etc...

C'est bien gentil mais chercher ma carte son, etc... pas cool hein ? et bien on va simplifier tout ça via du bash avec zenity... comme ça ce sera plus simple.

On va utiliser un petit programme que j'ai trouvé sur le net qui permet de faire une sélection sur X:

wget https://github.com/lolilolicon/ffcast/raw/master/xrectsel.c --no-check-certificate
$(grep -Eo "gcc(.*)" xrectsel.c)
su -c "install xrectsel /usr/local/bin/"

Cela a installé une commande nommé xrectsel sur votre système, dans /usr/local/bin

Reste à faire un script pour lire les coordonnées, choisir le périphérique de capture et enfin lancer la capture...

Plutôt que de chercher les infos dans /proc/asound/devices et cards, je vais utiliser une autre méthode, plus adapté au scripting, qui consiste à chercher les cartes et leur capacité dans /proc/asound/cardN où N est un numéro. En lisant les fichiers pcmNc/info, j'aurais toutes les informations nécessaires. Par exemple:

cat /proc/asound/card0/pcm0c/info
card: 0
device: 0
subdevice: 0
stream: CAPTURE
id: USB Audio
name: USB Audio
subname: subdevice #0
class: 0
subclass: 0
subdevices_count: 1
subdevices_avail: 1

Voici le script, moins de 100 lignes:

#!/bin/bash
#author Patrice Ferlet - Metal3d@gmail.com - http://www.metal3d.org
#Licence: GPLv3
 
#get Desktop dir for user
DESKTOP=$HOME/Desktop
if [[ -f ~/.config/user-dirs.dirs ]]; then
    source ~/.config/user-dirs.dirs
    DESKTOP=$XDG_DESKTOP_DIR
fi
 
getCards(){
    ## this function seeks every sound card that can be use to capture sound (mic, line in...)
 
    #find cards directory
    i=0
    capdevices=""
    while [[ -d /proc/asound/card$i ]]
    do
        #find pcmNc
        capdevices=$capdevices" "$(find /proc/asound/card$i -name "pcm*c" -type d)
        i=$((i+1))
    done
 
    for cap in $capdevices
    do
        #get options... index, subdevice etc...
        card=$(awk '/^card: /{print $2}' $cap/info)
        dev=$(awk '/^device: /{print $2}' $cap/info)
        subdev=$(awk '/^subdevice: /{print $2}' $cap/info)
        name=$(awk -F":" '/^name: /{print $2}' $cap/info)
        name=$(echo $name | sed 's/ /\-/g')
        echo "hw:$card,$dev,$subdev" "$name"''    
        echo
    done
 
}
 
__ffcast(){
    #lauch ffmpeg with options
    winsize=$1
    off=$2
    asound=$3
    options=$4
    file=$(echo "$options" | awk '{print $NF}')
 
    #run ffpmeg and get pid
    ffmpeg -f x11grab -s $winsize -r 30 -i :0.0+$off  -f alsa -i $asound $options &
    pid=$!
    zenity --notification \
        --window-icon /usr/share/icons/gnome/scalable/actions/media-record-symbolic.svg \
        --text "to stop ffcast, press icon" 2>/dev/null
    kill $pid
    zenity --info --title "Screencast stopped" --text "$file has been saved" 
}
 
chooseFFopts(){
    #this function allows you to choose output formats; it returns options + filename
    file=$DESKTOP/"screencast-"$(date +"%Y.%m.%d-%H:%M")
    ogv="-b 9000k $file.ogv"
    webm="-b 9000k $file.webm"
    avi="-b 9000k $file.avi"
    response=$(zenity --list --column "Format" avi x264 ogv) || exit 1
    echo ${!response}
}
 
main(){
    #main function
 
    captures=$(getCards)
    interface=$(zenity --title "Choose a sound device to capture" \
            --list --column "Port" \
            --column "Interface name" $captures) || exit 1
 
    #run xrectset to get a X rect selection made with mouse
    coords=$(xrectsel | sed 's/\+/ /')
    win=$(echo $coords | awk '{print $1}')
    offset=$(echo $coords | awk '{print $2}' | sed 's/\+/,/')
 
    #get ffmpeg options
    opts=$(chooseFFopts)
 
    #prepare screencast
    zenity --question \
        --title "Capture will begin after you press OK" \
        --text "An icon will appear in notification, press it to stop screencast"\
        --ok-label "Start screencast"\
        --cancel-label "Cancel" || exit 1
 
    #run screencast
    __ffcast $win $offset $interface "$opts"
}
 
#run main function
main

Sauvez ce fichier dans /usr/local/bin/ffmpeg-screencast (en root) et rendez le exécutable

su -c "chmod +x /usr/local/bin/ffmpeg-screencast"

Créez vous un lanceur dans le bureau, c'est plus sympa je trouve...

Vous le lancez, on vous propose de capturer l'audio sur ce qu'on trouve, puis vous faites une boite de sélection... reste ensuite à lancer le screencast. Une icone ronde apparait dans barre de notification, si vous cliquez dessus alors la capture s'arrête. Dans votre bureau apparait alors la capture vidéo que vous vouliez.

mysql-5.1.56

Remi Collet

Les RPM de MySQL Community Server 5.1.56 GA sont disponibles dans le dépôt remi pour RHEL et CentOS. Voir le Changelog.

Pas de RPM prévu pour fedora qui dispose de la version 5.5.9, passée en GA (stable).

Cette construction utilise un fichier .spec proche de celui de f14.  Le plugin InnoDB (version 1.0.15 GA) est aussi disponible, le fichier de configuration (/etc/my.cnf) contient les options pour l'active (sauf pour EL-4) ATTENTION : avant la mise à jour, une sauvegarde de vos bases de données est très vivement conseillée (un vidage avec... Lire mysql-5.1.56

Extension RRD pour PHP

Remi Collet

Une nouvelle extension rrd, permettant la gestion des fichiers rrdtool en PHP est disponible.

Une extension rrdtool (fournie par rrdtool-php) existe déjà, mais elle ne semble plus très active.

Le paquet php-pecl-rrd est disponible dans le dépôt remi pour fedora et EL 6.

L'extension rrd ne semble pas une solution de remplacement directe de l'extension rrdtool, les fonctions fournies sont en effet différentes $ php -r 'print_r(get_extension_funcs("rrdtool"));'Array(    [0] => rrd_graph    [1] => rrd_fetch    [2] => rrd_error    [3] => rrd_clear_error    [4] => rrd_update    [5] => rrd_last    [6] => rrd_create   ... Lire Extension RRD pour PHP

libmemcached-0.47

Remi Collet

Le RPM de la nouvelle version 0.47 de la biliothèque libmemcached de communication avec le serveur memcached est disponible dans le dépôt remi pour Fedora et Enterprise Linux. Il est aussi dans le dépôt rawhide (et fedora 15).

Comme toujours : yum --enablerepo=remi install libmemcached Cette bibliothèque est nécessaire à l'extension PECL memcached, (une nouvelle alternative à memcache) en plein développement. Cette mise à jour cassant l'ABI avec la version 0.43, je ne prévois pas de MAJ dans les dépôts fedora ≤ 14. (l'ABI est compatible avec les versions 0.44 et 0.46)... Lire libmemcached-0.47

Divertissement du Vendredi: GnuBG - Backgammon, un jeu qu'il est bien !

Paquet Fedora du jour

GNU BackgammonVoici un jeu dont m'a parlé vince sur un article précédent.

Le Backgammon est un jeu de stratégie plus simple que le jeu de Go, il est d'origine grecque-turque. Ce jeu se joue à l'aide de dès, il laisse alors un peu de place à la chance, ce qui permet des retournements de situations incroyables (sauf si l'on joue vraiment bien !).

En Grèce tous les bars mettent à disposition des clients des plateaux, autant dire que c'est un jeu populaire ! On y joue en sirotant un café frappé :)" class="smiley Si je me souviens bien : 1 cuillère de café à diluer, 3 de sucre, rajouter un peu d'eau et passer au mixeur : ça fait plein de mousse onctueuse, rajouter des glaçons et une paille.

Bon je dois avouer que comme ça sans lire le manuel du jeu, je n'ai rien compris !!! :)" class="smiley Mais voilà de quoi tenter d'apprendre à jouer : Fédération française de backgammon.
A priori il y a un mode apprentissage, de plus vous avez visiblement ce qu'il faut pour vous aider à améliorer votre jeu à l'aide d'algorithmes permettant de donner des statistiques de réussites sur votre prochain coup.

Bonne partie !!!

Installation en ligne de commande : yum install gnubg

Installation avec l'interface graphique : Jeux > A backgammon game and analyzer

Localisation dans le menu : Applications -> Jeux -> GNU Backgammon

Lancement en ligne de commande : /usr/bin/gnubg

Site web : http://www.gnubg.org/

Premiers pas avec QtScript

Fabien Nicoleau

Dans un précédent billet, j'avais parlé de la possibilité d'intégrer très facilement dans vos applications Java des scripts écrits en JavaScript, et de la facilité avec laquelle vos applications peuvent interagir avec les scripts. J'avais ensuite proposé un exemple d'utilisation avec un robot IRC fonctionnant avec des plugins écrits en JavaScript.

La bibliothèque Qt permet elle aussi d'intégrer des scripts JavaScript dans vos applications. Je propose ici de découvrir comment le faire, à travers quelques exemples simples.

Avant de commencer

Avant d'entrer dans le vif du sujet, préparons d'abord le terrain. Je proposerai pour chaque exemple le code dans ce billet, mais je vous conseille, si vous voulez tester, de télécharger l'archive jointe à ce billet contenant les sources des exemples. Une fois décompressée, déplacez vous dans le dossier qtscripting, puis ouvrez une console, et tapez :

qmake-qt4
make

Tous les exemples sont alors compilés. Bien sûr, pour que la compilation fonctionne, ils vous faut installer le paquet qt-devel. Sous Fedora, tapez :

# yum install qt-devel

Une fois les exemples compilés, vous pouvez vous déplacer dans les dossiers, et lancer les exécutables.

Notez que pour ajouter le support des scripts au projet, il a simplement suffit d'ajouter script à la directive QT (voir le QT += script dans le fichier common.pri), et d'include QtScript dans les sources.

Exemple 1 : 1 + 1

Pour le premier exemple, faisons simple ! Il s'agit ici simplement de voir comment exécuter un code JavaScript depuis du code C++, et de récupérer le résultat.

On commence direct avec le code :

#include <QtScript>
#include <QApplication>
int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QScriptEngine engine;
    QScriptValue resultat = engine.evaluate("1+1");
    qDebug() << resultat.toString() ;
    return 0;
}

Rien de complexe. On créé d'abord un objet de type QScriptEngine, qui sera notre moteur de script, indispensable. On demande ensuite à notre moteur d'évaluer le code "1+1". Le résultat de l'évaluation est stocké dans un objet de type QScriptValue. Enfin on affiche le résultat. En parcourant la doc sur QScriptValue, vous pourrez vous rendre compte qu'il est possible d'effectuer de nombreuses vérifications afin de s'assurer que le résultat est exploitable, notamment en contrôlant son type.

Voilà pour un début, il n'y a rien d'exceptionnel bien sûr, mais les base sont posées : notre programme a affiché le résultat d'un code externe (en l'occurrence du JavaScript, même si ce n'est qu'une addition, et que le code est "en dur" dans le programme). Pour les plus sceptiques, j'affiche la sortie du programme :

[eponyme@localhost exemple1]$ ./exemple1
"2"
[eponyme@localhost exemple1]$

Surpris ? :D

Passons à la suite.

Exemple 2 : appel d'une fonction

Nous allons dans cette exemple appeler une fonction et lui passer un paramètre, puis afficher ce qu'elle nous renvoie. Le code :

#include <QtScript>
#include <QApplication>
int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QScriptEngine engine;
    engine.evaluate("function disMoiBonjour(prenom) { return \"Bonjour \"+prenom; }");    
    QScriptValue disBonjour = engine.globalObject().property("disMoiBonjour");
    qDebug() << disBonjour.call(QScriptValue(),QScriptValueList() << "Fabien").toString() ;
    return 0;
}

Comme dans le premier exemple, on créé un moteur, mais cette fois ci au lieu de lui faire évaluer une addition, nous demandons d'évaluer la définition d'une fonction, appelée disMoiBonjour. Cette fonction retourne une phrase "disant bonjour" à la personne dont le prénom est passé en paramètre. La ligne suivante nous permet de récupérer parmi les objets du script (globalObject())  notre fonction disMoiBonjour (property()), conservée dans la variable disBonjour. Il ne nous reste plus qu'à l'appeler grâce à la méthode call(). Notez le second paramètre, qui est une liste de valeurs qui sont passées en arguments à la fonction appelée. Ici, on envoie juste la chaîne "Fabien".

Voici la sortie du programme :

[eponyme@localhost exemple2]$ ./exemple2
"Bonjour Fabien"
[eponyme@localhost exemple2]$

Cet article ayant juste pour but de découvrir des choses simples et basiques possibles avec QtScript, je ne rentre pas plus dans les le détail concernant les différentes méthodes utilisées ici, mais la documentation vous fera découvrir que l'on peut aller beaucoup plus loin.

Au passage, on voit déjà que du code JavaScript dans une chaine de caractères, ça n'est pas très pratique. Vivement qu'on puisse le mettre dans un fichier !

Exemple 3 : code JS dans un fichier et objet global

Pour le moment, nos scripts étaient "en dur" dans le code C++, ce qui n'a que très peu (aucun ?) intérêt. Voyons ici comment externaliser ce code et le placer dans un fichier. La méthode evaluate() prenant en paramètre une chaine de caractères, il sera très simple (surtout avec Qt) de récupérer le contenu d'un fichier texte pour le faire évaluer. Je profite aussi de cet exemple pour montrer comment exporter depuis le code C++ un objet global dans le script. Comme d'habitude, on attaque directement avec le code :

#include <QtScript>
#include <QApplication>
int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QScriptEngine engine;
    QFile file("script.qs");
    file.open(QIODevice::ReadOnly);
    engine.globalObject().setProperty("name","Fabien");
    engine.evaluate(file.readAll());   
    file.close();
    return 0;
}

Comme on pouvait s'y attendre, la chose est très simple à réaliser grâce à l'objet QFile. On ouvre en lecture seule un fichier nommé script.qs, et on passe son contenu à la méthode evaluate() via la méthode readAll(). Le contenu du fichier est ainsi entièrement évalué. L'autre nouveauté ici est que l'on "envoie" dans le script l'objet "name", dont la valeur est "Fabien", avec la méthode setProperty(). Ainsi, à n'importe quel endroit du script, il sera possible d'accéder à cet objet.

Voyons d'ailleurs le contenu du script (fichier script.qs) :

print('Bonjour '+name);

Ce petit script se contentera donc d'afficher dans la console un bonjour à la personne dont le prénom est stocké dans l'objet name (et assigné depuis le code C++).

Voyons ce que ca donne à l'exécution :

[eponyme@localhost exemple3]$ ./exemple3
Bonjour Fabien
[eponyme@localhost exemple3]$

La encore, pas de grande surprise ! Mais désormais, vous pouvez stocker votre code JS dans un fichier, ce qui ouvre un grand nombre de possibilités, notamment celui de stocker différents scripts afin de charger différentes fonctions, pour un système de plugins.

Exemple 4 : envoi d'un QObject dans le script

L'exemple 3 nous a montré qu'il est possible d'envoyer un objet avec une valeur dans le script, et ce depuis le code C++. Cependant cet objet ne peut prendre qu'une valeur simple. Nous allons voir ici comment envoyer dans le script un QObject (et donc un de ses objets hérités, ce qui en fait beaucoup).

Pour illustrer cet exemple, je vais utiliser un QLabel, habituellement utilisé pour afficher un libellé dans une interface graphique. Voici le code :

#include <QtScript>
#include <QApplication>
#include <QLabel>
int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QLabel lbl;
    QScriptEngine engine;
    QFile file("script.qs");
    file.open(QIODevice::ReadOnly);
    lbl.setText("UN");
    QScriptValue object = engine.newQObject(&lbl);
    engine.globalObject().setProperty("label",object);   
    engine.evaluate(file.readAll());
    file.close();
    qDebug() <<"Dans le code : " <<  lbl.text();
    return 0;
}

Le QLabel ne sera pas utilisé ici dans une interface, mais on utilise ses méthodes pour le manipuler. Après l'habituelle création du moteur, on créé donc un objet QLabel, pour lequel on modifie le libellé en le passant à "UN", grâce au slot setText(). Ensuite, la méthode newQObject() du moteur est appelée, prenant en paramètre un pointeur sur notre objet de type QLabel. C'est la valeur renvoyée par newQObject qui est utilisée pour le setProperty() de la ligne suivante, déjà utilisé dans l'exemple 3. Ainsi, dans notre script, on pourra utiliser notre objet QLabel n'importe quand grâce à la variable label, dont le nom est passé en premier argument à setProperty(). Comme dans les autres exemples, on évalue le script, puis on ferme le fichier. Enfin, on affiche la valeur de notre QLabel grâce à sa méthode text(). En toute logique, elle devrait renvoyer "UN", à moins que la valeur ait été changée depuis le script ... Voyons justement le code de ce dernier (fichier script.qs) :

print("Dans le script : "+label.text);
label.setText("DEUX");

Deux lignes, très simples. La première affiche la valeur du QLabel accessible grâce à la variable label. La valeur du QLabel est obtenue grâce à la propriété text de ce dernier. Sur la seconde ligne, on change la valeur du QLabel à "DEUX", grâce à setText().

Voyons ce que donne l'exécution :

[eponyme@localhost exemple4]$ ./exemple4
Dans le script : UN
Dans le code :  "DEUX"
[eponyme@localhost exemple4]$

On voit ici l'évolution de notre QObject ! La première valeur affichée ("UN") depuis le script (avec print()) est celle qui avait été fixée dans le code C++. Après avoir affiché la valeur, le script JS a changé la valeur du QLabel, et depuis le code, la valeur affichée est bien "DEUX".

Nous pouvons donc de façon très simple passer à notre script JS des QObject et lui permettre d'en modifier les propriétés.

Exemple 5 : gestion des erreurs

Lorsque l'on débute, ou lorsque l'on commence à faire des choses compliquées, il arrive souvent que l'on bloque car le code JS n'est pas évalué. Dans la plupart des cas, il s'agit juste d'une erreur de syntaxe. Mais il est parfois difficile de savoir pourquoi est ce que notre script n'est pas évalué, et donc qu'il est impossible d'interagir avec lui ensuite. On peut aussi être parfois sûr de son code, et ne pas penser qu'il y a une erreur. Heureusement il est possible, lorsqu'une erreur est rencontrée, d'afficher un message. Voici un code d'exemple :

#include <QtScript>
#include <QApplication>
int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QScriptEngine engine;
    QScriptValue result = engine.evaluate("print('Bonjour !'");
    if (result.isError()) {
        qDebug() << result.property("message").toString();
    }
    return 0;
}

Dans ce code, on demande au moteur d'évaluer du JavaScript devant afficher "Bonjour !", mais la parenthèse fermante est volontairement oubliée. On se sert de la valeur renvoyée par l'évaluation pour vérifier s'il y a eu une erreur avec isError(). Si c'est le cas, on peut afficher un message explicatif en récupérant la propriété message du résultat d'évaluation.

Voyons l'exécution du programme :

[eponyme@localhost exemple5]$ ./exemple5
"Parse error"
[eponyme@localhost exemple5]$

Notre code n'est pas évalué, et le moteur nous indique une Parse error. On sait au moins ou chercher. Cette vérification vous permettra de gagner un peu de temps si vous n'obtenez pas le résultat espéré.

Exemple 6 : signaux et slots

Les signaux et slots sont l'un des avantages du développement avec la bibliothèque Qt, et n'ont pas été oubliés avec QtScript. Dans ce dernier exemple, nous allons créer une fenêtre basique comprenant deux boutons. Le premier, appelé "Bonjour", devra afficher "Bonjour !" dans la console lorsque l'on clique dessus, et le second, "Au revoir", devra afficher ... "Au revoir !" (et oui !)  lorsque l'on clique dessus. La particularité est que ces affichages dans la console se feront depuis un script JS, et non pas directement depuis des slots dans le code C++. L'intérêt ? Ici, aucun. Il s'agira simplement de montrer que l'on peut connecter un signal à un slot dont l'implémentation est faite dans un script JS, ce qui permet de personnaliser facilement une application en changeant le comportement du slot dans les scripts. Pour l'exemple, nous verrons deux façons différentes de connecter un signal à un slot implémenté dans un script, la première sera faite depuis le code C++, pour le bouton "Bonjour", et la seconde directement dans le script JS, pour le bouton "Au revoir".

Passons au code :

#include <QtScript>
#include <QApplication>
#include <QtGui>
int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QWidget fenetre;
    QVBoxLayout vbox(&fenetre);
    QPushButton bBonjour("Bonjour");
    QPushButton bAuRevoir("Au revoir");
    vbox.addWidget(&bBonjour);
    vbox.addWidget(&bAuRevoir);

    QScriptEngine engine;
    QFile file("script.qs");
    file.open(QIODevice::ReadOnly);
    QScriptValue objBonjour = engine.newQObject(&bBonjour);
    QScriptValue objAuRevoir = engine.newQObject(&bAuRevoir);
    engine.globalObject().setProperty("objAuRevoir",objAuRevoir);
    engine.evaluate(file.readAll());
    file.close();
    QScriptValue slot = engine.globalObject().property("bonjourHandler");
    qScriptConnect(&bBonjour, SIGNAL(clicked()), objBonjour, slot);

    fenetre.show();
    return app.exec();
}

C'est un peu plus long que d'habitude, certes, mais le premier pavé ne concerne que l'interface graphique, ce qui n'est pas le sujet de ce billet. On y créé les deux boutons et on les place sur la fenêtre.

Ensuite, comme d'habitude, on créé un moteur, qui évaluera du code JS placé dans un fichier. Deux "objets QtScript" sont créés à partir des deux boutons, grâce à newQObject() : objBonjour et objAuRevoir. Ils nous serviront à réaliser les connexions avec les slots du script. L'objet objAuRevoir est exporté dans le script car nous en aurons besoin pour réaliser la connexion au slot

Une fois l'évaluation du script faite, on récupère la propriété bonjourHander, qui est une fonction dans le script JS, que l'on stocke dans la variable slot. Cette variable est utilisée ensuite pour réaliser la connexion entre le signal clicked du bouton "Bonjour" et le slot bonjourHandler, grâce à la fonction qScriptConnect().

Voyons maintenant le contenu du script (fichier script.qs) :

function bonjourHandler () {
    print('Bonjour !');
}
function auRevoirHandler () {
    print('Au revoir !');
}
objAuRevoir.clicked.connect(this.auRevoirHandler);

On y trouve les deux fonctions qui seront appelées lors des clics sur les boutons. bonjourHandler est déjà connectée au bouton "Bonjour" via l'appel à qScriptConnect() dans le code C++. La fonction auRevoirHandler est elle connectée au bouton "Au revoir" à la dernière ligne du script, qui utilise l'objet objAuRevoir exporté dans le programme. Ainsi nos deux fonctions sont connectées à leur bouton respectif, l'une depuis le code C++, l'autre depuis le script JS. A vous de voir ce que vous préférez !

Une petite image pour l'exécution du programme :

tuto_qtscript_exemple6.jpg


C'est sur cet exemple que ce termine cette initiation. Je n'ai pas la prétention avec cet article de donner une vue d'ensemble des possibilités offertes par QtScript. J'en suis d'ailleurs encore au stade de la découverte. Mais ces exemples pourrons vous permettre de vous lancer, et de démystifier un peu les choses ! Je proposerai dans un prochain article un exemple concret d'utilisation de QtScript pour un système de plugins.

Hormis les liens disséminés un peu partout dans l'article, les deux sources qui m'ont le plus aidé sont :

Bon dev' !


Fabien (eponyme)

Premiers pas avec QtScript

Fabien Nicoleau

Dans un précédent billet, j'avais parlé de la possibilité d'intégrer très facilement dans vos applications Java des scripts écrits en JavaScript, et de la facilité avec laquelle vos applications peuvent interagir avec les scripts. J'avais ensuite proposé un exemple d'utilisation avec un robot IRC fonctionnant avec des plugins écrits en JavaScript.

La bibliothèque Qt permet elle aussi d'intégrer des scripts JavaScript dans vos applications. Je propose ici de découvrir comment le faire, à travers quelques exemples simples.

Avant de commencer

Avant d'entrer dans le vif du sujet, préparons d'abord le terrain. Je proposerai pour chaque exemple le code dans ce billet, mais je vous conseille, si vous voulez tester, de télécharger l'archive jointe à ce billet contenant les sources des exemples. Une fois décompressée, déplacez vous dans le dossier qtscripting, puis ouvrez une console, et tapez :

qmake-qt4
make

Tous les exemples sont alors compilés. Bien sûr, pour que la compilation fonctionne, ils vous faut installer le paquet qt-devel. Sous Fedora, tapez :

# yum install qt-devel

Une fois les exemples compilés, vous pouvez vous déplacer dans les dossiers, et lancer les exécutables.

Notez que pour ajouter le support des scripts au projet, il a simplement suffit d'ajouter script à la directive QT (voir le QT += script dans le fichier common.pri), et d'include QtScript dans les sources.

Exemple 1 : 1 + 1

Pour le premier exemple, faisons simple ! Il s'agit ici simplement de voir comment exécuter un code JavaScript depuis du code C++, et de récupérer le résultat.

On commence direct avec le code :

#include <QtScript>
#include <QApplication>
int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QScriptEngine engine;
    QScriptValue resultat = engine.evaluate("1+1");
    qDebug() << resultat.toString() ;
    return 0;
}

Rien de complexe. On créé d'abord un objet de type QScriptEngine, qui sera notre moteur de script, indispensable. On demande ensuite à notre moteur d'évaluer le code "1+1". Le résultat de l'évaluation est stocké dans un objet de type QScriptValue. Enfin on affiche le résultat. En parcourant la doc sur QScriptValue, vous pourrez vous rendre compte qu'il est possible d'effectuer de nombreuses vérifications afin de s'assurer que le résultat est exploitable, notamment en contrôlant son type.

Voilà pour un début, il n'y a rien d'exceptionnel bien sûr, mais les base sont posées : notre programme a affiché le résultat d'un code externe (en l'occurrence du JavaScript, même si ce n'est qu'une addition, et que le code est "en dur" dans le programme). Pour les plus sceptiques, j'affiche la sortie du programme :

[eponyme@localhost exemple1]$ ./exemple1
"2"
[eponyme@localhost exemple1]$

Surpris ? :D

Passons à la suite.

Exemple 2 : appel d'une fonction

Nous allons dans cette exemple appeler une fonction et lui passer un paramètre, puis afficher ce qu'elle nous renvoie. Le code :

#include <QtScript>
#include <QApplication>
int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QScriptEngine engine;
    engine.evaluate("function disMoiBonjour(prenom) { return \"Bonjour \"+prenom; }");    
    QScriptValue disBonjour = engine.globalObject().property("disMoiBonjour");
    qDebug() << disBonjour.call(QScriptValue(),QScriptValueList() << "Fabien").toString() ;
    return 0;
}

Comme dans le premier exemple, on créé un moteur, mais cette fois ci au lieu de lui faire évaluer une addition, nous demandons d'évaluer la définition d'une fonction, appelée disMoiBonjour. Cette fonction retourne une phrase "disant bonjour" à la personne dont le prénom est passé en paramètre. La ligne suivante nous permet de récupérer parmi les objets du script (globalObject())  notre fonction disMoiBonjour (property()), conservée dans la variable disBonjour. Il ne nous reste plus qu'à l'appeler grâce à la méthode call(). Notez le second paramètre, qui est une liste de valeurs qui sont passées en arguments à la fonction appelée. Ici, on envoie juste la chaîne "Fabien".

Voici la sortie du programme :

[eponyme@localhost exemple2]$ ./exemple2
"Bonjour Fabien"
[eponyme@localhost exemple2]$

Cet article ayant juste pour but de découvrir des choses simples et basiques possibles avec QtScript, je ne rentre pas plus dans les le détail concernant les différentes méthodes utilisées ici, mais la documentation vous fera découvrir que l'on peut aller beaucoup plus loin.

Au passage, on voit déjà que du code JavaScript dans une chaine de caractères, ça n'est pas très pratique. Vivement qu'on puisse le mettre dans un fichier !

Exemple 3 : code JS dans un fichier et objet global

Pour le moment, nos scripts étaient "en dur" dans le code C++, ce qui n'a que très peu (aucun ?) intérêt. Voyons ici comment externaliser ce code et le placer dans un fichier. La méthode evaluate() prenant en paramètre une chaine de caractères, il sera très simple (surtout avec Qt) de récupérer le contenu d'un fichier texte pour le faire évaluer. Je profite aussi de cet exemple pour montrer comment exporter depuis le code C++ un objet global dans le script. Comme d'habitude, on attaque directement avec le code :

#include <QtScript>
#include <QApplication>
int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QScriptEngine engine;
    QFile file("script.qs");
    file.open(QIODevice::ReadOnly);
    engine.globalObject().setProperty("name","Fabien");
    engine.evaluate(file.readAll());   
    file.close();
    return 0;
}

Comme on pouvait s'y attendre, la chose est très simple à réaliser grâce à l'objet QFile. On ouvre en lecture seule un fichier nommé script.qs, et on passe son contenu à la méthode evaluate() via la méthode readAll(). Le contenu du fichier est ainsi entièrement évalué. L'autre nouveauté ici est que l'on "envoie" dans le script l'objet "name", dont la valeur est "Fabien", avec la méthode setProperty(). Ainsi, à n'importe quel endroit du script, il sera possible d'accéder à cet objet.

Voyons d'ailleurs le contenu du script (fichier script.qs) :

print('Bonjour '+name);

Ce petit script se contentera donc d'afficher dans la console un bonjour à la personne dont le prénom est stocké dans l'objet name (et assigné depuis le code C++).

Voyons ce que ca donne à l'exécution :

[eponyme@localhost exemple3]$ ./exemple3
Bonjour Fabien
[eponyme@localhost exemple3]$

La encore, pas de grande surprise ! Mais désormais, vous pouvez stocker votre code JS dans un fichier, ce qui ouvre un grand nombre de possibilités, notamment celui de stocker différents scripts afin de charger différentes fonctions, pour un système de plugins.

Exemple 4 : envoi d'un QObject dans le script

L'exemple 3 nous a montré qu'il est possible d'envoyer un objet avec une valeur dans le script, et ce depuis le code C++. Cependant cet objet ne peut prendre qu'une valeur simple. Nous allons voir ici comment envoyer dans le script un QObject (et donc un de ses objets hérités, ce qui en fait beaucoup).

Pour illustrer cet exemple, je vais utiliser un QLabel, habituellement utilisé pour afficher un libellé dans une interface graphique. Voici le code :

#include <QtScript>
#include <QApplication>
#include <QLabel>
int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QLabel lbl;
    QScriptEngine engine;
    QFile file("script.qs");
    file.open(QIODevice::ReadOnly);
    lbl.setText("UN");
    QScriptValue object = engine.newQObject(&lbl);
    engine.globalObject().setProperty("label",object);   
    engine.evaluate(file.readAll());
    file.close();
    qDebug() <<"Dans le code : " <<  lbl.text();
    return 0;
}

Le QLabel ne sera pas utilisé ici dans une interface, mais on utilise ses méthodes pour le manipuler. Après l'habituelle création du moteur, on créé donc un objet QLabel, pour lequel on modifie le libellé en le passant à "UN", grâce au slot setText(). Ensuite, la méthode newQObject() du moteur est appelée, prenant en paramètre un pointeur sur notre objet de type QLabel. C'est la valeur renvoyée par newQObject qui est utilisée pour le setProperty() de la ligne suivante, déjà utilisé dans l'exemple 3. Ainsi, dans notre script, on pourra utiliser notre objet QLabel n'importe quand grâce à la variable label, dont le nom est passé en premier argument à setProperty(). Comme dans les autres exemples, on évalue le script, puis on ferme le fichier. Enfin, on affiche la valeur de notre QLabel grâce à sa méthode text(). En toute logique, elle devrait renvoyer "UN", à moins que la valeur ait été changée depuis le script ... Voyons justement le code de ce dernier (fichier script.qs) :

print("Dans le script : "+label.text);
label.setText("DEUX");

Deux lignes, très simples. La première affiche la valeur du QLabel accessible grâce à la variable label. La valeur du QLabel est obtenue grâce à la propriété text de ce dernier. Sur la seconde ligne, on change la valeur du QLabel à "DEUX", grâce à setText().

Voyons ce que donne l'exécution :

[eponyme@localhost exemple4]$ ./exemple4
Dans le script : UN
Dans le code :  "DEUX"
[eponyme@localhost exemple4]$

On voit ici l'évolution de notre QObject ! La première valeur affichée ("UN") depuis le script (avec print()) est celle qui avait été fixée dans le code C++. Après avoir affiché la valeur, le script JS a changé la valeur du QLabel, et depuis le code, la valeur affichée est bien "DEUX".

Nous pouvons donc de façon très simple passer à notre script JS des QObject et lui permettre d'en modifier les propriétés.

Exemple 5 : gestion des erreurs

Lorsque l'on débute, ou lorsque l'on commence à faire des choses compliquées, il arrive souvent que l'on bloque car le code JS n'est pas évalué. Dans la plupart des cas, il s'agit juste d'une erreur de syntaxe. Mais il est parfois difficile de savoir pourquoi est ce que notre script n'est pas évalué, et donc qu'il est impossible d'interagir avec lui ensuite. On peut aussi être parfois sûr de son code, et ne pas penser qu'il y a une erreur. Heureusement il est possible, lorsqu'une erreur est rencontrée, d'afficher un message. Voici un code d'exemple :

#include <QtScript>
#include <QApplication>
int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QScriptEngine engine;
    QScriptValue result = engine.evaluate("print('Bonjour !'");
    if (result.isError()) {
        qDebug() << result.property("message").toString();
    }
    return 0;
}

Dans ce code, on demande au moteur d'évaluer du JavaScript devant afficher "Bonjour !", mais la parenthèse fermante est volontairement oubliée. On se sert de la valeur renvoyée par l'évaluation pour vérifier s'il y a eu une erreur avec isError(). Si c'est le cas, on peut afficher un message explicatif en récupérant la propriété message du résultat d'évaluation.

Voyons l'exécution du programme :

[eponyme@localhost exemple5]$ ./exemple5
"Parse error"
[eponyme@localhost exemple5]$

Notre code n'est pas évalué, et le moteur nous indique une Parse error. On sait au moins ou chercher. Cette vérification vous permettra de gagner un peu de temps si vous n'obtenez pas le résultat espéré.

Exemple 6 : signaux et slots

Les signaux et slots sont l'un des avantages du développement avec la bibliothèque Qt, et n'ont pas été oubliés avec QtScript. Dans ce dernier exemple, nous allons créer une fenêtre basique comprenant deux boutons. Le premier, appelé "Bonjour", devra afficher "Bonjour !" dans la console lorsque l'on clique dessus, et le second, "Au revoir", devra afficher ... "Au revoir !" (et oui !)  lorsque l'on clique dessus. La particularité est que ces affichages dans la console se feront depuis un script JS, et non pas directement depuis des slots dans le code C++. L'intérêt ? Ici, aucun. Il s'agira simplement de montrer que l'on peut connecter un signal à un slot dont l'implémentation est faite dans un script JS, ce qui permet de personnaliser facilement une application en changeant le comportement du slot dans les scripts. Pour l'exemple, nous verrons deux façons différentes de connecter un signal à un slot implémenté dans un script, la première sera faite depuis le code C++, pour le bouton "Bonjour", et la seconde directement dans le script JS, pour le bouton "Au revoir".

Passons au code :

#include <QtScript>
#include <QApplication>
#include <QtGui>
int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QWidget fenetre;
    QVBoxLayout vbox(&fenetre);
    QPushButton bBonjour("Bonjour");
    QPushButton bAuRevoir("Au revoir");
    vbox.addWidget(&bBonjour);
    vbox.addWidget(&bAuRevoir);

    QScriptEngine engine;
    QFile file("script.qs");
    file.open(QIODevice::ReadOnly);
    QScriptValue objBonjour = engine.newQObject(&bBonjour);
    QScriptValue objAuRevoir = engine.newQObject(&bAuRevoir);
    engine.globalObject().setProperty("objAuRevoir",objAuRevoir);
    engine.evaluate(file.readAll());
    file.close();
    QScriptValue slot = engine.globalObject().property("bonjourHandler");
    qScriptConnect(&bBonjour, SIGNAL(clicked()), objBonjour, slot);

    fenetre.show();
    return app.exec();
}

C'est un peu plus long que d'habitude, certes, mais le premier pavé ne concerne que l'interface graphique, ce qui n'est pas le sujet de ce billet. On y créé les deux boutons et on les place sur la fenêtre.

Ensuite, comme d'habitude, on créé un moteur, qui évaluera du code JS placé dans un fichier. Deux "objets QtScript" sont créés à partir des deux boutons, grâce à newQObject() : objBonjour et objAuRevoir. Ils nous serviront à réaliser les connexions avec les slots du script. L'objet objAuRevoir est exporté dans le script car nous en aurons besoin pour réaliser la connexion au slot

Une fois l'évaluation du script faite, on récupère la propriété bonjourHander, qui est une fonction dans le script JS, que l'on stocke dans la variable slot. Cette variable est utilisée ensuite pour réaliser la connexion entre le signal clicked du bouton "Bonjour" et le slot bonjourHandler, grâce à la fonction qScriptConnect().

Voyons maintenant le contenu du script (fichier script.qs) :

function bonjourHandler () {
    print('Bonjour !');
}
function auRevoirHandler () {
    print('Au revoir !');
}
objAuRevoir.clicked.connect(this.auRevoirHandler);

On y trouve les deux fonctions qui seront appelées lors des clics sur les boutons. bonjourHandler est déjà connectée au bouton "Bonjour" via l'appel à qScriptConnect() dans le code C++. La fonction auRevoirHandler est elle connectée au bouton "Au revoir" à la dernière ligne du script, qui utilise l'objet objAuRevoir exporté dans le programme. Ainsi nos deux fonctions sont connectées à leur bouton respectif, l'une depuis le code C++, l'autre depuis le script JS. A vous de voir ce que vous préférez !

Une petite image pour l'exécution du programme :

tuto_qtscript_exemple6.jpg


C'est sur cet exemple que ce termine cette initiation. Je n'ai pas la prétention avec cet article de donner une vue d'ensemble des possibilités offertes par QtScript. J'en suis d'ailleurs encore au stade de la découverte. Mais ces exemples pourrons vous permettre de vous lancer, et de démystifier un peu les choses ! Je proposerai dans un prochain article un exemple concret d'utilisation de QtScript pour un système de plugins.

Hormis les liens disséminés un peu partout dans l'article, les deux sources qui m'ont le plus aidé sont :

Bon dev' !


Fabien (eponyme)

Bleachbit et votre PC souffle un peu

Patrice Ferlet

On télécharge, on joue avec des compilations de programme, on se teste au package, on ferme brutalement des éditeurs de texte, on utilise firefox et google-chrome... et puis un jour on se rend compte que son PC est un peu lent, que le disque "craque" et que l'espace disque commence à manquer. Je vais vous présenter l'outil magique qui va vous soulager la douleur.

Bleachbit est un outil très intéressant pour tout utilisateur qui remplis son disque dur très vite, qui navigue énormément sur internet ou encore qui fait pas mal de code... en fait, il est bon pout tout le monde, y compris l'utilisateur bureautique.

Bleachbit vient en fait avec des "plugins" qui s'activent si il découvre une utilisation possible sur votre PC, par exemple si vous utilisez aMule alors l'outil vous proposera de nettoyer votre espace aMule, idem pour Firefox, Google-Chrome, etc...

Pour utiliser ce programme, installez le via l'outil de gestion de paquets ou dans une console:

su -lc "yum -y install bleachbit"

Vous pouvez alors le lancer en tant qu'utilisateur ou root. Pour le second cas, cela sera utile pour nettoyer les cache de yum par exemple... Bref, lancez l'outil avec la commande "bleachbit" (le plus simple étant de presser ALT+F2 et de taper dans l'invite: bleachbit)

S'ouvre alors une fenêtre de ce type: Bleachbit

En cochant des cases, vous activerez alors les opérations possible de bleachbit. En tant qu'utilisateur vous ne pourrez pas toucher à yum, mais par contre les fichiers temporaires (inutiles en général) ou l'optimisation les bases SQLite de firefox ou chrome est une opération qui peut vous faire gagner beaucoup de place.

Personnellement, je code beaucoup sous vim, gedit et geany. J'ai pas mal de compilation dans mon répertoire de rpm (rpmbuild) et j'utilise énormément de cache dans mes navigateurs étant donné le nombre de site que je visite en une journée. J'ai gagné 9 gigas lors de mon dernier nettoyage.

En tant que root, c'est une opération qui peut vous faire gagner quelques centaines de mégas rien qu'en vidant les cache yum et les traduction inutiles (désolé mais les man pages en polonais ça m'aide pas des masses..)

Pour ce dernier cas notez bien que les mises à jour de page de manuels vous feront apparaître un "warning" qui stipule que des fichiers sont manquants. Oui, c'est normal et pas grave du tout...

Voilà, moi je vous conseille d'utiliser cet outil de temps en temps. Commencez toujours par utiliser le bouton "Prévisualiser" qui vous donnera une estimation de l'espace que vous allez retrouver (presque toujours inférieur au gain réél). Et surtout, lisez bien les informations sur la gauche quand vous sélectionner une option pour savoir ce que va faire Bleachbit.

Mais dans l'ensemble, il ne fait rien de bien dangereux.

La GUI du Jeudi : System-config-services - Une interface de gestion de service

Paquet Fedora du jour

system-config-servicesSystem-config-services est un petit utilitaire vous permettant de configurer l'arrêt, le démarrage ou encore redémarrage de vos services. Il ne s'arrête pas à ces fonctionnalités là puisqu'il permet aussi de déterminer si tel ou tel service doit être lancé automatiquement au démarrage !
Enfin, si vous le désirez, il permettra aussi de personnaliser le niveau dexécution de chacun de vos services.

Bref, petit utilitaire indispensable si l'on ne souhaite pas utiliser service et chkconfig en ligne de commande !

Installation en ligne de commande : yum install system-config-services yum install system-config-services-docs

Installation avec l'interface graphique : Outils Système > Utility to start and stop system services

Localisation dans le menu : Système > Administration > Services

Lancement en ligne de commande : /usr/bin/system-config-services

Site web : http://fedorahosted.org/system-config-services

Désactiver les bips système sous Linux/BSD.

Sébastien Natroll Les bips système, c’est geek, c’est chouette, mais ça peut vite devenir importunant lorsque l’on est pas seul. Pour le désactiver : GNU/Linux # modprobe -r pcspkr # echo "blacklist pcspkr" >> /etc/modprobe.d/blacklist.conf /!\ N.B : Ne pas inscrire rmmod pcspkr dans /etc/rc.local comme l’indiquent certains sites. C’est un peu crade… BSD # sysctl hw.syscons.bell=0 La suite >

Désactiver les bips système sous Linux/BSD.

Sébastien Natroll Les bips système, c’est geek, c’est chouette, mais ça peut vite devenir importunant lorsque l’on est pas seul. Pour le désactiver : GNU/Linux # modprobe -r pcspkr # echo "blacklist pcspkr" >> /etc/modprobe.d/blacklist.conf /!\ N.B : Ne pas inscrire rmmod pcspkr dans /etc/rc.local comme l’indiquent certains sites. C’est un peu crade… BSD # sysctl hw.syscons.bell=0 La suite >

Firefox 4.0 Beta 12

Remi Collet

Les RPM de la douzième beta de la prochaine version majeure du navigateur de la Fondation Mozilla est disponible dans le dépôt remi pour Fedora >= 10. Disponible en 78 langues.

Le paquet firefox4-4.0-0.26.beta12 installe cette nouvelle version à côté de la version 3.x. Vous aurez donc 2 options dans le menu Internet. Commencez par lire : Mozilla Firefox 4 Beta Release Notes (Notes de version en anglais) A propos de Firefox 4 Beta (Tristan Nitot). Comme toujours : yum remove firefox4yum --enablerepo=remi install... Lire Firefox 4.0 Beta 12

Mardi Artistique : Wallpapoz - Avoir un fond d'écran différent par bureau

Paquet Fedora du jour

WallpapozCet outil vous permet d'avoir un fond d'écran différent par bureau Gnome ! Wallpapoz est véritablement très simple à configurer, vous choisissez le bureau, un fond d'écran et celui-ci se voit défini un fond d'écran spécifique !
Un démon est alors lancé, ainsi wallpapoz tourne en tache de fond. Vous avez aussi la possibilité de changer de fond d'écran après un temps que vous définissez.
Il est à noter qu'avec Compiz d'activé, le chargement du fond d'écran n'est pas instantané, il y a un petit décalage de 1 ou 2 secondes tout au plus ... mais j'avoue ne pas avoir cherché plus loin comment résoudre ce problème.
Voilà de quoi bidouiller votre belle Fedora pour ce début de semaine hivernale !

Installation en ligne de commande : yum install wallpapoz

Installation avec l'interface graphique : Bureau Gnome > Gnome Multi Backgrounds and Wallpapers Configuration Tool

Localisation dans le menu : Applications > Accessoires > Wallpapoz

Lancement en ligne de commande : /usr/bin/wallpapoz

Site web : http://wallpapoz.akbarhome.com/

Réseau en mode bridge avec KVM sous F-14

Johan Cwiklinski

Depuis un certain temps maintenant, j'utilise les fonctionnalités de virtualisation offertes de base par Fedora, à savoir : KVM/Qemu, libvirt et les outils virt-manager, virsh, etc.

Par défaut, les machines virtuelles utiliseront un réseau NAT avec un sous réseau 192.168.122.0. J'ai voulu récemment que le routeur de mon réseau local s'occupe d'attribuer une adresse IP à l'une de mes machines virtuelles ; il fallait donc revoir la configuration du réseau pour passer en mode bridge sur mon unique carte réseau.

Sous Fedora 14 ; une partie du travail est déjà faite... La configuration par défaut ajoute une interface nommée virbr0 que nous allons pouvoir utiliser en tant que bridge.

Pour ce faire, on va créer le fichier de configuration pour l'interface virbr0 (/etc/sysconfig/network-scripts/ifcfg-virbr0) avec le contenu suivant :

DEVICE=virbr0
ONBOOT=yes
BOOTPROTO=dhcp
TYPE=Bridge
USERCTL=yes
NM_CONTROLLED=no
IPV6INIT=no
NAME="bridge"
PEERNTP=yes

Ici, on spécifie entre autres qu'il s'agit d'un bridge et que la configuration se fait par DHCP (puisque c'est mon routeur qui doit se charger de ça).

Ensuite, on indiquera à l'interface eth0 qu'elle doit utiliser le bridge , en ajoutant à la fin du fichier /etc/sysconfig/network-scripts/ifcfg-eth0:

 BRIDGE=virbr0

Un petit service network restart après, on peut constater que les adresses IP des machines virtuelles sont désormais gérées par le routeur, ainsi que l'attribution d'adresses IP fixes en fonction des adresses MAC, etc.

Notez que la configuration énoncée ici se réfère à l'utilisation du service network, et non NetworkManager. Il faudra donc veiller à ce que ce dernier soit désactivé au profit du service network.

Mon hébergeur : KalyHost !

Sébastien Natroll J’ai récemment renouvelé Kenshin-blog.com pour un an. Aujourd’hui je me suis dit : « Pourquoi ne pas en parler ? ». Vous allez me dire : « C’est un billet sponsorisé, ça craint. » ou alors « On s’en fout », et je tiens à clarifier de suite les choses. Ce billet n’est pas sponsorisé, je n’ai pas besoin d’être payé La suite >

Mon hébergeur : KalyHost !

Sébastien Natroll J’ai récemment renouvelé Kenshin-blog.com pour un an. Aujourd’hui je me suis dit : « Pourquoi ne pas en parler ? ». Vous allez me dire : « C’est un billet sponsorisé, ça craint. » ou alors « On s’en fout », et je tiens à clarifier de suite les choses. Ce billet n’est pas sponsorisé, je n’ai pas besoin d’être payé La suite >

Page générée le 02 sept 2015 à 02:17