Category Archives: Tutorial

S’auto-héberger avec un serveur Fanless sur un système GNU/Debian.

Historique des versions

Version Date Auteur Description
0.1 (draft) 22 Mars 2010 Renaud Guezennec Montage d’un serveur fanless, installation système, déploiement des premiers services (ssh et apache2) et configuration réseau.

Introduction

Faire du vrai internet, c’est facile. Ce tutorial présente les étapes à effectuer. Vous comprendrez que vous en êtes pleinement capable:
Si vous savez lire, que vous êtes motivés et un minimum patient, vous y arriverez.

Pourquoi héberger son site soi-même? Pour des raisons d’indépendance: Je souhaite être la seule personne capable couper ma machine du réseau. Je veux savoir où sont stockés mes fichiers. Faite de votre internet un point intelligent du réseau.
N’utilisez pas internet comme un minitel 2.0.J’ai fais le choix de monter un serveur fanless (sans ventilateur), pour deux raisons principales:

  • Le bruit : un ordinateur qui est destiné à fonctionner 24h/24 doit être silencieux.
  • L’économie d’énergie : mes choix techniques sont principalement voués à réduire la consommation électrique de l’appareil. Il existe des solutions bien plus performante que ma solution de ce point de vue, là.

Matériel

Le matériel que j’ai choisi n’est pas vraiment la solution la plus économique. Il est vrai qu’essayer de monter un serveur fanless n’est pas encore très facile; j’espère ouvrir un peu la voie.
On arrive dans des domaines assez inconnus. C’est très rare de trouver des cartes mères passives.
Les boitiers ont souvent un petit ventillo pour l’alimentation ou les disques. J’ai aussi souhaité avoir une capacité en disque importante, cette condition élimine la plupart des solutions tout en un. Je n’avais pas envie d’avoir une boitier relier à un disque dur externe ou une clé USB. Cependant, sachez que ces solutions existent!

Je vous communique les références des différentes pièces que j’ai achetées.

Montage

Les pièces utiles:

ensemble des composantsle lecteur CD est vraiment optionnel, je n’en ai pas eu besoin.

La carte mère:

carte mèreLe côté pratique, c’est que les cartes mères atom sont fournies avec le cpu déjà installé et sûrement soudé à la carte. L’installation en est plus facile mais ça empèche toute évolution matérielle par la suite.

le boitier:

boitierCe boitier est mal agencé, je trouve. Il est gros pour pas grand chose. Le support disque dur n’accueille qu’un disque alors qu’il y a la place d’en mettre bien plus. C’est d’ailleur ce que j’ai fait.

Installation de la carte mère:

La première chose à dire, c’est que le montage ce n’est pas facile. J’ai déjà monté pas mal d’ordinateurs. Celui-ci fut assez pénible. L’absence de documentation pour le boitier est vraiment un problème. La carte mère se colle directement sur le fond du boitier. Il n’y pas les habituelles chemises.

installationLes cables d’alimentations sont assez mal fichus. Ils sont trop long et surtout le socle du lecteur de CD gène énormément. Par chance, vous pouvez enlever les socles CD et disque. Faites-le pour vous dégager l’espace. Sans ça, le branchement des LED power/disque et des USB sera très compliqué. Pour les disques, j’ai branché le premier sur le socle prévu à cet effet. Le deuxième repose sur un lit de polystirène sous le premier.
Après plusieurs tentatives, ça ne démarré pas. J’ai débranché le lecteur CD, vérifié certains branchements puis il a enfin démarré.

Installation du système et des services

Je suis un fidèle du système de paquet DEB, créer par/pour la distribution debian. J’utilise Ubuntu pour mon poste de travail mais pour un serveur, une vraie debian est bien mieux [Ce n’est que mon avis].
Dans les autres distributions pour faire un serveur, je dirais que Gentoo me parait un bon choix. (Elle reste cependant assez compliqué au premier abord.)
Comment installe-t-on un système debian?

Télécharger les bons fichiers

J’ai installé Debian Lenny. Les images ont été téléchargées le 05/03/2010.
J’ai opté pour un installation assez exotique. Démarrer sur clé USB qui embarque une image iso minimale (netinst).

L’image à copier sur la clé s’appelle boot.img.gz
Une fois l’image téléchargée, il suffit de l’écrire sur votre clé usb (attention, ça écrasera tout le reste) par la commande:

# zcat boot.img.gz /dev/sdX

(La commande sudo ne marche pas. Faite-le en root! C’est surement une histoire de droit de l’utilisateur sur les périphériques).

Montez la clé:

# mount /dev/sdX /mnt

Deux images peuvent être utilisées: la “netinst” et la “businesscard”. J’ai choisi la netinst, elle est très légère, l’installation est très minimaliste (à condition de choisir les bonnes options), cependant le système doit être sur internet pour l’installation.

Pour télécharger l’image netinst :

debian-504-i386-netinst.iso
Copier l’image dans la clé:

# cp /chemin/vers/image/iso/debian-504-i386-netinst.iso /mnt/

Installer sa GNU/Debian

Démarrer l’installation, rien de plus facile. Il suffit de brancher la clé usb puis de démarrer la machine. On voit la still picture (le logo du fabriquant de la carte mère). Vint, en suite, l’écran de choix de la langue de l’installateur debian.

langueJ’ai choisi anglais en langue et un clavier français. Après cet écran, le mini système GNU/Linux cherchera sur la clé installéei, l’image iso à utiliser. L’installeur vous demandera de définir les partitions. J’ai crée deux partitions sur le premier disque: le swap et le point de montage / . Mon swap fait 20 go, ça devrai être suffisant. Le deuxième disque est monté sur /home. Après l’étape des disques, il faudra choisir le type d’installation. Par défaut, la version desktop est sélectionné. J’ai choisi l’installation du strict minimum. Il vous posera des questions pour définir le mot de passe root et le login/password de votre utilisateur.

A l’aboutissement de l’installation, vous redémarrez l’ordinateur en débranchant la clé usb. Maintenant, votre ordinateur est fonctionnel. Nous pouvons lui installer les services et outils nécessaires pour le transformer en vrai serveur.

Installation des premiers services

Le service des services, le premier pas du voyage, c’est le serveur SSH. Afin d’administer son serveur à distante, plus besoin d’écran et de clavier. Ensuite, apache2 le serveur web, l’arme noble pour l’expression de vos libertés. PHP5 pour créer des sites coté serveur. Vim, l’éditeur en ligne de commande que je préfère. Le serveur mysql avec son support php afin d’utiliser une base de données pour vos sites. En dernier lieu, php5-gd c’est un module assez utile pour php.

# apt-get install openssh-server
# apt-get install apache2
# apt-get install php5
# apt-get install vim
# apt-get install mysql-server php5-mysql
# apt-get install php5-gd

Sécurisation des premiers services

Configuration ssh server (la base d’une bonne sécurité)

Editer en root, le fichier /etc/ssh/sshd_config.
Changer le port par défaut (22) par un port quelconque. C’est une sécurité contre les attaques de force brute:
Port 22 en Port 9999
vous pouvez prendre n’importe quelle valeur comprise entre 1024 et 65536. (plus d’info)
Désactiver l’autorisation de login en root directement. Cela augmente la complexité pour forcer le passage. Les méchants devront trouver votre login et mot de passe. De plus, il est plus propre de se connecter en tant qu’utilisateur normal.
PermitRootLogin yes en PermitRootLogin no
Cette option est pour les utilisateurs avancés. Il vous faudra mettre dans votre serveur une clé ssh. Cela rend l’authentification plus sûre.
PasswordAuthentication yes en PasswordAuthentication no

Voici une copie de mon fichier de configuration:

# Package generated configuration file
# See the sshd(8) manpage for details

# What ports, IPs and protocols we listen for
Port 999
# Use these options to restrict which interfaces/protocols 
# sshd will bind to
#ListenAddress ::
#ListenAddress 0.0.0.0
Protocol 2
# HostKeys for protocol version 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
#Privilege Separation is turned on for security
UsePrivilegeSeparation yes

# Lifetime and size of ephemeral version 1 server key
KeyRegenerationInterval 3600
ServerKeyBits 768

# Logging
SyslogFacility AUTH
LogLevel INFO

# Authentication:
LoginGraceTime 120
PermitRootLogin no
StrictModes yes

RSAAuthentication yes
PubkeyAuthentication yes
#AuthorizedKeysFile	%h/.ssh/authorized_keys

# Don't read the user's ~/.rhosts and ~/.shosts files
IgnoreRhosts yes
# For this to work you will also need host keys
# in /etc/ssh_known_hosts
RhostsRSAAuthentication no
# similar for protocol version 2
HostbasedAuthentication no
# Uncomment if you don't trust ~/.ssh/known_hosts 
# for RhostsRSAAuthentication
#IgnoreUserKnownHosts yes

# To enable empty passwords, change to yes (NOT RECOMMENDED)
PermitEmptyPasswords no

# Change to yes to enable challenge-response passwords
# (beware issues with some PAM modules and threads)
ChallengeResponseAuthentication no

# Change to no to disable tunnelled clear text passwords
PasswordAuthentication no

# Kerberos options
#KerberosAuthentication no
#KerberosGetAFSToken no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes

# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes

X11Forwarding no
X11DisplayOffset 10
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
#UseLogin no

#MaxStartups 10:30:60
#Banner /etc/issue.net

# Allow client to pass locale environment variables
AcceptEnv LANG LC_*

Subsystem sftp /usr/lib/openssh/sftp-server

UsePAM yes

Connexion & réseau

L’auto-hébergement nécessite certaines conditions à propos de votre connexion internet. Elle ne sont pas obligatoire mais cela facilite grandement la vie. Il faut une connexion en continue: type adsl ou (encore mieux) fibre optique, éviter les contrats limités à un volume de données transmis. Personnellement, je n’ai jamais utilisé les “machinBox”. Préférant acheter un modem/routeur configurable: j’utilise le Netgear DG834G et le Netgear DGN2000. Je suis très content de ses deux modèles. Il est facile d’ouvrir les ports et rediriger vers telle ou telle machine. Le contrôle du DHCP permet une gestion élégante de votre réseau LAN.

Hypothèse: vous avez deux machines différentes dans votre LAN réliée à un routeur/modem.

La première des choses à faire est de s’assurer que le serveur recevra toujours la même ip au sein du réseau LAN. Pour cela, il y a deux possibilités:

  • IP fixe dans le LAN
  • Utilisation d’un serveur DHCP bien configuré

Je déconseille la première solution. Elle nécessite la configuration de chaque poste, une mauvaise configuration peut entrainé des conflits d’adresse IP. De plus, l’ajout d’une nouvelle machine vous obligera à configurer celle-ci.
La 2ème méthode est plus souple. Votre routeur/modem donne l’adresse IP pour chaque machine et pour fixer les adresses IP, il se fonde sur les adresses MAC.
L’adresse MAC est une sorte de numéro d’immatriculation de votre carte réseau. Il est “normalement” unique au monde. (Dans les faits, il peut être changer logiciellement donc…)
Il est donc possible d’obliger votre modem/routeur à donner l’adresse 192.168.0.3 à votre serveur, l’adresse 192.168.0.2 à votre pc de bureau et de spécifier que pour toutes autres machines, la plage 192.168.0.10 à 192.168.0.120 doit être utilisé.
Pour éviter les problèmes, je vous conseillerais de désactiver le Wi-Fi de votre réseau. Ce n’est pas une technologie très sûre.

La machine serveur reçoit toujours la même ip ? Il est temps de passer à la redirection des ports. Les 1024 premiers ports sont réservés à des usages définis. Par exemple, le port standard d’un serveur http est le 80: www.trucmuche.org et www.trucmuche.org:80 sont strictement identiques dans un navigateur.
Quelques autres ports/protocoles à connaitre (ou pas):

  • https: 440
  • FTP: 20 et 21
  • ssh: 22
  • smtp(mail) : 25
  • DNS: 53

Nous voulons rendre accessible notre serveur sur la toile. Le port 80 doit renvoyer vers l’ip du serveur. Toutes les demandes sur le port 80 à l’adresse: 80.80.80.80 seront transmises vers l’ip 192.168.0.3.
La même chose doit être faite pour chaque service qui tourne sur votre serveur et que vous voulez accessible depuis l’extérieur. Le ssh, par exemple, est maintenant sur le port 9999. Parametrez votre routeur/modem afin d’acheminer les connexions sur le port 9999 vers votre serveur. Pour réaliser le chapitre suivant, la redirection du port 53 est nécessaire.

Dynamique Name Server

C’est une partie que je maitrise moins. Je vais donc expliquer ce que j’ai compris. Vous avez acheté un nom de domaine: trucmuche.org. vous voudriez maintenant qu’il pointe vers votre serveur homemade dans votre placard? Il y a en gros, deux solutions: Gérer son DNS à la maison. ou le faire gérer par quelqu’un d’autre (probablement votre FAI ou votre registar).
Le premier cas est la solution la plus éducative et la plus souple: Si vous avez choisi cette option (comme moi), il faut installer bind9. Bind est le soft qui fait marcher internet. Il est le serveur DNS. Les DNS traduisent un nom de domaine en adresse ip.

Pour l’installer:

# apt-get install bind9

La configuration est bien plus complexe. Etudiont d’abord, la hiérarchie des fichiers de configuration.

homemade:~# ls -l /etc/bind/
total 48
-rw-r--r-- 1 root root  237 2009-12-20 21:21 db.0
-rw-r--r-- 1 root root  271 2009-12-20 21:21 db.127
-rw-r--r-- 1 root root  237 2009-12-20 21:21 db.255
-rw-r--r-- 1 root root  353 2009-12-20 21:21 db.empty
-rw-r--r-- 1 root root  270 2009-12-20 21:21 db.local
-rw-r--r-- 1 root root 2878 2009-12-20 21:21 db.root
-rw-r--r-- 1 root bind  907 2009-12-20 21:21 named.conf
-rw-r--r-- 1 root bind  240 2010-03-17 21:24 named.conf.local
-rw-r--r-- 1 root bind  572 2010-03-17 21:50 named.conf.options
-rw-r----- 1 bind bind   77 2010-03-17 21:05 rndc.key
-rw-r--r-- 1 root root 1317 2009-12-20 21:21 zones.rfc1918

Les fichiers de forme db.* sont des fichiers de configuration de zone dns; (nous verrons dans quelques instants, comment créer la zone pour trucmuche.org). Le fichier named.conf.options est le fichier de configuration du serveur. named.conf ne doit pas être modifier enfin sauf si vous êtes un super expert de la mort qui tue. Il convient de modifier named.conf.local pour ajouter notre zone.

Déclarons une zone sous la responsabilité de notre dns.

zone "trucmuche.org" {
	type master;
	file "/etc/bind/db.trucmuche.org";
};

Il y a deux type de zone: master (primaire) et slave (secondaire). Un nom de domaine est forcément attaché, au minimum, à deux serveurs dns: un seul primaire et un (ou plusieurs) secondaire. Le serveur primaire fait loi, les secondaires se mettront à jour par rapport à lui. Créer un fichier, /etc/bind/db.trucmuche.org Il doit contenir ceci:

$ORIGIN trucmuche.org.
$TTL 3h
@       IN      SOA     ns.trucmuche.org. gamemaster.trucmuche.org. (
                                2010031703
                                8H
                                2H
                                1W
                                1D )

@       	IN  NS  ns.trucmuche.org.

@       	IN  MX  10   mail2.trucmuche.org.

@  			IN	A	80.80.80.80


ns			IN	A	80.80.80.80
mail2   	IN	A   80.80.80.80
wiki    	IN	CNAME	trucmuche.org.
forum       IN  CNAME   trucmuche.org.
www         IN  CNAME   trucmuche.org.
};

La première ligne n’est pas importante, elle définit une variable à l’intérieur pour faciliter l’écriture du fichier de conf. Le TTL est le temps de valider des informations de votre zone. Il convient de définir une zone SOA.

  • 2010031703 : Serial sorte de numero de version de la configuration, on utilise en général la date du jour plus un champ 00 qu’on incrémente à chaque modification.
  • 8H : Rafraichissement: le serveur secondaire se mettra à jour en respectant ce temps ci.
  • 2H : retry : temps d’attente avant de réessayer quand une requête de mise à jour à échouer.
  • 1W : Expire : Temps après lequel la zone est gelée si les dns secondaire ne peuvent se mettre à jour.
  • 1D : Semblable à TTL.

@ IN NS ns.trucmuche.org.
Vous définissez le serveur de nom (DNS) qui définit la zone courante.
@ IN MX 10 mail2.trucmuche.org.
Vous définissez le serveur de mail principal de votre domaine.
@ IN A 80.80.80.80
Vous définissez l’ip principale de votre domaine, N’oubliez pas remplacer 80.80.80.80 par votre ip fixe.

ns 		IN	A   80.80.80.80
mail2   	IN	A   80.80.80.80

Définition des adresses ip pour votre serveur de nom et courriel.

wiki    	IN	CNAME	trucmuche.org.
forum       IN  CNAME   trucmuche.org.
www         IN  CNAME   trucmuche.org.

Définition de sorte d’alias, ainsi {wiki,forum,www}.trucmuche.org pointeront vers trucmuche.org. C’est apache (le serveur web) qui fera l’aiguillage.

Configuration Apache

Introduction

Apache, le serveur web du monde libre, le support de votre liberté d’expression, votre megaphone du web. Pour le rendre fonctionnel et l’adapter à vos besoins, il est important de le configurer.
Les dossiers de configuration d’apache se trouve dans l’arboréscence /etc/apache2/

-rw-r--r-- 1 root root 10104 2009-11-14 21:20 apache2.conf
drwxr-xr-x 2 root root  4096 2010-03-05 23:24 conf.d
-rw-r--r-- 1 root root   378 2009-11-14 21:20 envvars
-rw-r--r-- 1 root root    21 2010-03-07 12:59 httpd.conf
drwxr-xr-x 2 root root  4096 2010-03-05 23:24 mods-available
drwxr-xr-x 2 root root  4096 2010-03-07 14:42 mods-enabled
-rw-r--r-- 1 root root   513 2009-11-14 21:20 ports.conf
drwxr-xr-x 2 root root  4096 2010-03-19 00:04 sites-available
drwxr-xr-x 2 root root  4096 2010-03-19 00:05 sites-enabled

Dans l’ordre, le fichier apache2.conf définit la configuration vitale du serveur. Il est déconseillé d’y toucher.
Ce fichier définit le comportement par défaut du serveur: nombre de thread, les chemins et/ou nom de fichier pour modifier la configuration localement.
Le dossier conf.d contient des fichiers de configurations pour des points très spécifique d’apache.
envvars définit des variables d’environnements, présentement, le groupe et l’utilisateur sous lequel apache2 tourne. (Par défaut, www-data)

httpd.conf est partiquement vide. Nous allons utiliser des virtualhosts donc ce fichier ne présente plus beaucoup d’intérêt.
mods-available est un dossier regroupeant les fichiers de conf des modules disponibles pour apache. Un module permet d’étendre les fonctionnalités d’apache. Php est intégré dans apache sous la forme de module. Le support du ssl est aussi un module, il en existe beaucoup et vous pouvez même créer le votre, si cela vous intéresse.mods-enabled regroupe des liens symboliques vers les fichiers de configuration du module présents dans mods-available. Il faut bien comprendre qu’un module présent dans mods-available regroupe les modules activables et mods-enabled regroupe les modules activés. Pour activer un module, il suffit de placer les fichiers du module dans le dossier mods-enabled.

Dans le même principe, les dossiers sites-available et sites-enabled sont réspectivement le dossier des sites internet disponibles et le des sites internet actifs. Là encore, il est bon de créer un fichier de configuration dans available et d’ajouter un lien dans enabled. Nous verrons dans la partie virtuals hosts, comment configurer son site ou plutôt ses sites.

Utilisateur et droit

Il y a plusieurs moyens de gérer un serveur apache au niveau des droits. Cela dépend beaucoup de votre utilisation et de votre philosophie. Les différents choix:

  1. Votre serveur, c’est le votre. Il n’hebergera que votre site et rien d’autre.
  2. Votre serveur hébergera un gros site (par exemple le site d’une association, ou un site divisé en plusieurs sous-domaines: forum, wiki et www). Ils seront géré par vous et une poignée d’élus.
  3. Vous voulez que chaque utilisateur de votre serveur aie un site web et un compte utilisateur.
Le cas #1

La situation la plus facile. Vous n’avez pas d’accès à ouvrir. Vous pouvez coder/mettre à jour votre site par ssh. Vous n’aurais pas besoin de FTP.
Je vous conseille de créer un dossier “trucmuche” dans /home/toto. Votre utilisateur (toto) aura tous les droits sur votre futur site et apache sera limité.
Render l’utilisateur www-data membre du groupe toto. Pour cela, éditer le fichier /etc/group comme ceci.

# vi /etc/group

Ajouter www-data à la fin de la ligne toto:

toto:x:1000:www-data

Assurez-vous que le groupe toto ait les droits de lecture sur l’ensemble des sous-dossiers et fichiers présents dans /home/toto/trucmuche. Si vous voulez permettre à votre site uploader des fichiers, le serveur aura besoin des droits en écriture sur le répertoire de destination. C’est un effort de codage sur votre site. Cette configuration est propre et minimaliste.

Si cette vision vous convient sauter directement à la section Cas 1 : virtual host
Si vous cherchez une solution plus puissante et moins minimaliste, vous pouvez lire les sections suivantes.

Le cas #2

C’est déjà plus risqué. Je vous conseillerais de créer un utilisateur webmaster et de créer un dossier dans /home/webmaster/ par site web: [/home/webmaster/www,/home/webmaster/wiki,/home/webmaster/forum]. En termes de droits, il suffit de rendre www-data membre du groupe webmaster:

# vi /etc/group

Ajouter www-data à la fin de la ligne webmaster:

webmaster:x:1001:www-data

Si vous déployez des outils libres, comme un CMS, un wiki et un forum. Il vous suffira de créer des comptes administrateurs dans ces outils.
Si vous voulez donner un accès plus direct. Il est possible de mettre en place un FTP ou bien de donner les identifiants de webmaster.
[Il est encore plus intelligent de créer un utilisateur pour chaque “élu” et de rendre ces utilisateurs membre du groupe webmaster. Les fichiers devront être modifiable par les membres du groupe. Cependant, il vous sera plus facile de connaitre l’identité d’une personne responsable d’une bétise/erreur].

Si cette description répond à votre besoin aller directement à la section Cas 2 : virtual host

Le cas #3

Le plus complèxe des trois à mettre en place. Vous voulez que chaque utilisateur dispose d’un dossier particulier dans leur home (html_public ou www). Ils auront un accès direct au serveur par ssh ou FTP. Chaque utilisateur aura une base de données. Ce cas est assez fréquent dans les universités et/ou hébergeurs. Pour des raisons de sécurités, je vous conseillerais de ne pas donner d’accès ssh.

Cette configuation est relativement complexe, je vous conseillerais de jouer un peu avec les cas précédents. Afin de bien, vous faire la main sur les fichiers de configuration apache et autres.

La gestion des droits est délicate. Il y a plusieurs approches:

  • Rendre tout le monde membre du groupe d’apache [www-data]
  • l’opposé; n’ajouter personne mais les fichiers devront être accessible en lecture pour tous le monde.
  • Le troisième cas, éxécuter apache avec les droits d’un autre utilisateur (voir la section Cas 3 : virtual host)

les virtuals hosts

Ces cas typiques sont des exemples. N’hesitez pas à mélanger les solutions techniques.

Un site unique (cas 1)

La première chose à faire est de créer un dossier dans votre home /home/toto/monsite/.

$ mkdir /home/toto/monsite

Il faut ensuite créer un lien de

/var/www/

vers

/home/toto/monsite/

. Pour cela, tapez la commande suivante dans un terminal (root):

# cd /var/www
# ln -s /home/toto/monsite site

N’oubliez pas de vérifier les droits du groupe.

Ouvrez le fichier /etc/apache2/site-enabled/000-default pour y mettre ceci :
[Les lignes commençant par # sont des commentaires, je les utilise pour expliquer]

<VirtualHost 192.168.0.3:80>
    ServerAdmin toto@trucmuche.org
    ServerName trucmuche.org

    DocumentRoot /var/www/site1/
    #nous définissons le dossier racine du site.
    <Directory /var/www/site1>
        Options Indexes FollowSymLinks
        # Indexes : autorise apache à générer des indexes.
        # nous autorisons apache à suivre les liens symboliques. 
        # Important car /var/www/site1/ est un lien symbolique 
        # vers /home/toto/monsite/
        AllowOverride All
        # Nous autorisons Apache à changer sa configuration 
        # si un fichier .htaccess existe dans le dossier 
        # /var/www/site1
        Order allow,deny
        # Ordre de description des règles
        allow from all
        # Autorise tout le monde 
        # (pas besoin de règle d'interdiction)
        # Vous pouvez ajouter une plage d'ip interdite 
        # avec une ligne du genre Deny from XXX.XXX.XXX.XXX/XXX 
    </Directory>

    
    ErrorLog /var/log/apache2/error.log

# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
    LogLevel warn

    CustomLog /var/log/apache2/access.log combined
    ServerSignature On

     # Configuration par défaut des logs
     # A savoir: 
     # Niveau de log: avertissement (warm). 
     # [debug, info, notice, warn, error, crit]
     # Fichier d'enregistrement des logs dans:
     # /var/log/apache2/access.log 
     # La signature du serveur est activée.


    
    Alias /phpMyAdmin/ "/var/www/phpMyAdmin/"
    <Directory "/var/www/phpMyAdmin/">
        AllowOverride None
        Order allow,deny
        Deny from all
        Allow from 192.168.0.0/24 
        #on restrint l'accès au gestionnaire de base de données.
        #Seule les adresses de type 192.168.0.XXX seront acceptées. 
    </Directory>
    
</VirtualHost>
Un gros site avec sous-domaine (cas 2)

Je vais prendre, dans cet exemple, trois sous-domaines : www, wiki et forum qui afficheront respectivement la page principale du site, un wiki et un forum. La première étape consiste à créer 3 fichiers de configuration dans /etc/apache2/sites-available (en root).

# cd /etc/apache2/sites-available
# touch wiki.trucmuche.org
# touch forum.trucmuche.org
# touch www.trucmuche.org

Il convient ensuite d’installer les différents logiciels. A titre d’exemple, je vous explique la marche à suivre pour installer mediawiki, fluxbb et drupal.

Positionnez-vous, d’abord, dans le répertoire de votre utilisateur webmaster (Il faut être l’utilisateur webmaster).
Téléchargement des logiciels et installation:

$ cd /home/webmaster
$ wget http://download.wikimedia.org/mediawiki/1.15/mediawiki-1.15.1.tar.gz
$ wget http://fluxbb.org/download/releases/1.4-rc1/fluxbb-1.4-rc1.tar.gz
$ wget http://ftp.drupal.org/files/projects/drupal-6.16.tar.gz

$ tar -xzvf drupal-6.16.tar.gz
$ mv drupal-6.16/ drupal

$ tar -xzvf fluxbb-1.4-rc1.tar.gz
$ mv fluxbb-1.4-rc1/ forum

$ tar -xzvf mediawiki-1.15.1.tar.gz
$ mv mediawiki-1.15.1/ wiki

Après cette étape, vous devriez avoir les dossiers : wiki, forum et drupal dans /home/webmaster
Il faut maintenant faire la configuration du serveur apache pour qu’il aille chercher les fichiers au bon endroit.
Commençons par drupal (qui sera www.trucmuche.org): Éditez le ficher : /etc/apache2/sites-available/www.trucmuche.org qui est normalement vide.

<VirtualHost *:80>
	ServerName www.trucmuche.org
    #definition du sous-domaine
	ServerAdmin webmaster@trucmuche.org
	
	DocumentRoot /var/www/webmaster/drupal
	<Directory /home/www/webmaster/drupal>
		Options Indexes FollowSymLinks MultiViews
		AllowOverride All
		Order allow,deny
		Allow from all
	</Directory>
	ErrorLog /var/log/apache2/error.log
	LogLevel warn
	CustomLog /var/log/apache2/trucmuche/trucmuche.log combined
    # Nous spécialisons le log de sortie pour clarifier les logs.
</VirtualHost>

Il faut faire la même chose pour le wiki et le forum:

<VirtualHost *:80>
	ServerName wiki.trucmuche.org
	ServerAdmin webmaster@trucmuche.org
	
	DocumentRoot /var/www/webmaster/wiki
	<Directory /home/www/webmaster/wiki>
		Options Indexes FollowSymLinks MultiViews
		AllowOverride All
		Order deny,allow
		Deny from all
		Allow from 127.0.0.0/255.0.0.0 ::1/128			
	</Directory>
	ErrorLog /var/log/apache2/error.log
	LogLevel warn
   CustomLog /var/log/apache2/trucmuche/wiki.trucmuche.log combined
</VirtualHost>
<VirtualHost *:80>
	ServerName forum.trucmuche.org
	ServerAdmin webmaster@trucmuche.org
	
	DocumentRoot /var/www/webmaster/forum
	<Directory /home/www/webmaster/forum>
		Options Indexes FollowSymLinks MultiViews
		AllowOverride All
		Order deny,allow
		Deny from all
		Allow from 127.0.0.0/255.0.0.0 ::1/128			
	</Directory>
	ErrorLog /var/log/apache2/error.log
	LogLevel warn
CustomLog /var/log/apache2/trucmuche/forum.trucmuche.log combined
</VirtualHost>

Pour finaliser la configuration, il faut créer des liens symboliques dans /etc/apache2/sites-enabled/

# cd /etc/apache2/sites-enabled/
# ln -s ../sites-available/forum.trucmuche.org forum.trucmuche.org
# ln -s ../sites-available/wiki.trucmuche.org wiki.trucmuche.org
# ln -s ../sites-available/www.trucmuche.org www.trucmuche.org
L’usine à site (cas 3)

Je ne donnerai pas de fichier de configuration Apache dans cette section. Je vous conseillerais de regarder du côté des hotes virtuels dynamiques et/ou de la commande suEXEC.

Activer et configurer certains modules : url_rewrite et php5.

Les modules url_rewrite et php sont très utilisés. Ils apportent des fonctionnalités bien appréciables.
Pour les activer, il suffit de faire un lien de leurs fichiers de mods-available vers mods-enabled. [Il est possible qu’ils soient déjà activés par défaut.]

# cd /etc/apache2/mods-enabled/
# ln -s ../mods-available/php5.load php5.load
# ln -s ../mods-available/php5.load php5.conf
# ln -s ../mods-available/rewrite.load rewrite.load

Si vous voulez jouer avec la configuration de php5: éditer le fichier /etc/php5/apache2/php.ini.
Pour utiliser url_rewrite, il suffit d’activer le mode rewrite dans un .htaccess en spécifiant les règles de réécriture.

Installer une solution mail: Smtp + imap + spamAssassin

Section en cours d’écriture.

Script de sauvegarde & crontab

Il est important d’assurer la pérénité de ses données. C’est pourquoi, il est très fortement conseillé de mettre, en production, un serveur uniquement si un système de sauvegarde et restauration est fonctionnel. Les éléments à mettre dans une sauvegarde sont:

  • La hiérarchie de dossiers et fichiers du site/des sites
  • Un dump des bases de données
  • Les fichiers de configuration (si vous estimez que les modifications sont importantes)
  • Le dossier /home (dans le cas ou des utilisateurs ont des données autres que leur site web.)
#!/bin/sh
HOST='ftp.somewhere.fr'
USERFTP='toto@somewhere.fr'
USER=toto
PASSWDFTP='bidule'
PASSWDSQL='bidule'
DATE=`date +%d`
DRUPALFILE=/home/$USER/script/backup-drupal-file-$DATE.sql
WIKIFILE=/home/$USER/script/backup-wiki-file-$DATE.sql
FORUMFILE=/home/$USER/script/backup-forum-file-$DATE.sql

ARCHIVE=/home/$USER/monsite-$DATE.tar.gz
#tar le dossier /home/toto/monsite
tar -czvf $ARCHIVE /home/$USER/monsite


#dump de postgresql 
export PGPASSWORD=passwordPostgresql
pg_dump -f $DRUPALFILE -U $USER drupal 

#dump de mysql 
mysqldump --set-charset  -u $USER -p$PASSWDSQL wiki > $WIKIFILE
mysqldump --set-charset  -u $USER -p$PASSWDSQL forum > $FORUMFILE



ftp -n $HOST <<END_SCRIPT
quote USER $USERFTP
quote PASS $PASSWD
send $DRUPALFILE backup_drupal_$DATE.sql
send $WIKIFILE backup_wiki_$DATE.sql
send $FORUMFILE backup_forum_$DATE.sql
send $ARCHIVE monsite-$DATE.tar.gz

quit
END_SCRIPT
exit 0

Voilà, un exemple de script de sauvergarde. Il exporte deux bases de données mysql et d’une postgresql dans des fichiers .sql. Il fait aussi une archive du dossier /home/toto/monsite. Tous les fichiers ont le numero du jour du le mois (Ca fait une rotation de sauvegarde de 30 jours en moyennes). Les sauvegardes sont envoyer par FTP sur un autre serveur. Bien entendu, rien ne vous empêche d’améliorer ça. Vous trouverez des multitudes de scripts pour vous aider.
Il faut ensuite executer ce script de façon régulière. Crontab est là pour vous sauver. Tapez la commande suivantes pour ajouter une règle.

# crontab -e

Ajouter la ligne suivante dans le fichier.

0 0 * * * sh /home/toto/script/sauvegarde.sh

La sauvegarde se fera tous les jours à minuit.

Foire Aux Questions

Mon serveur semble ne pas marcher à l’extérieur de mon réseau local.

Vérifiez bien la configuration de votre routeur. Les connexions entrantes sur le port 80 (http) doivent être redirigées vers votre serveur.

Je n’arrive pas à uploader des fichiers.

C’est probablement un problème de droit en écriture sur le serveur. Apache doit pouvoir écrire dans le répertoire de partage choisi. (chmod g+w et chown user:www-data)

Plus d’informations

partage WebDav sur Ubuntu, Configuration des clients sous Ubuntu/Gnome, MacOS X et Windows XP

Introduction

Un serveur WebDav est un serveur web classique couplé avec un module pour faciliter l’envoie de fichier. Dans ce tutorial, Nous allons mettre en place un serveur webdav sur un serveur web Apache 2. Nous verrons ensuite que l’ensemble des systèmes d’exploitations fournissent un système transparent pour la connexion à ce genre de partage. Le client webdav est souvent inclus dans le navigateur de fichier.

Installer un serveur WebDav

Je pars du principe que vous avez un serveur Apache 2 fonctionnel sur votre serveur. Pour notre exemple, le dossier de partage sera le dossier /var/www/sharing. Le dossier de configuration d’apache est à l’adresse: /etc/apache2/. Les comptes utilisateurs (et leurs mots de passes) seront enregistrés dans le fichier : /var/www/sharing/.webdav.passwd

Les prérequis

La première étape est de générer un certificat SSL et une clé SSL. C’est primordial pour assurer le cryptage des données. Un certificat est un fichier avec l’extension .crt (server.crt dans ce tutorial) et la clé sera server.key. Pour créer la clé et le certificat, tapez ces commandes dans un terminal:

$ mkdir /tmp/ssl_conf 
$ cd /tmp/ssl_conf 
$ openssl req -config /etc/ssl/openssl.cnf -new -out server.csr

Définissez une passphrase, tapez un mot de passe mémorisable. Ensuite, répondez aux questions sur la localisation de votre serveur. (Il n’est pas nécessaire de répondre à toutes les questions.)

$ openssl rsa -in privkey.pem -out server.key 
$ openssl x509 -in server.csr -out server.crt -req -signkey server.key -days 3650 
$ openssl x509 -in server.crt -out server.der.crt -outform DER

Le certificat sera valable environ 10 ans.
La dernière étape pour l’instant est de copier/coller les deux fichiers importants dans le répertoire d’apache2.

# cp server.crt /etc/apache2/
# cp server.key /etc/apache2/

(Vous aurez besoin d’être root pour faire ça)

Configurer son serveur apache

Il y a 4 étapes à faire:
-Définir un virtualhost
-Activer le support SSL
-Activer le support WebDav
-Activer l’authentification http.

Voici le code du virtualhost à définir dans /etc/apache2/site-enable/000-default

<VirtualHost 192.168.1.2:443>
        ServerName toto
        DocumentRoot /var/www/sharing
        <Directory "/var/www/sharing">
                Options Indexes FollowSymLinks MultiViews
                AllowOverride None
                Order allow,deny
                Allow from all
        </Directory>

        SSLEngine on
        SSLCertificateFile /etc/apache2/server.crt
        SSLCertificateKeyFile /etc/apache2/server.key

        <Location />
            Dav on
            AuthType Basic
            AuthName "Sharing  Repository"
            AuthUserFile /var/www/sharing/.webdav.passwd
            Require valid-user
        </location>
</VirtualHost>

Définition des champs:
remplacez 192.168.1.2 par l’ip de votre machine sur le réseau local.
Le répertoire de partage sera /var/www/sharing

les lignes suivantes activent le support du ssl (https), en définissant également, les chemins vers les fichiers clé et certificat.

        SSLEngine on
        SSLCertificateFile /etc/apache2/server.crt
        SSLCertificateKeyFile /etc/apache2/server.key

Le dernier groupe de lignes active le webdav et spécifie la méthode d’authentification.

        <Location />
            Dav on
            AuthType Basic
            AuthName "Sharing  Repository"
            AuthUserFile /var/www/sharing/.webdav.passwd
            Require valid-user
        </location>

Pour résumer, nous avons maintenant un serveur configuré et un certificat ssl prêt pour le service. Il nous faut donc créer un fichier de .passwd et activer les modules webdav et ssl.

Créer un fichier de mot de passe

Une simple commande suffit pour créer ce fichier et ajouter l’utilisateur toto:

# htpasswd -c /var/www/sharing/.webdav.passwd toto

L’option -c crée le fichier, s’il n’existe pas. Le mot de passe vous sera demandé dans la suite de la commande. Il est conservé crypté dans le fichier.

Pour ajouter un autre utilisateur

# htpasswd /var/www/sharing/.webdav.passwd tata

Activer les modules webdav et ssl dans Apache2

Pour cela, il faut créer des liens symboliques dans les dossiers de configuration d’apache.

cd /etc/apache2/mods-enabled
ln -s ../mods-available/dav* .
ln -s ../mods-available/ssl* .

A ce stade, il vous reste plus qu’a redémarrer votre serveur apache.

sudo /etc/init.d/apache2 restart

Vous avez normalement un serveur webdav fonctionnel. Pour vérifier, tapez l’adresse de votre serveur dans un navigateur web. Acceptez le certificat, identifier vous grâce à votre login/mot de passe.
Vous devriez voir une page de ce style:

resultat webdav

Configuration des Clients

Nous allons maintenant voir comment configurer des clients WebDav. Pour télécharger des fichiers depuis le serveur un simple navigateur web suffit. Cependant le plus intéressant, reste la possibilité de déposer des fichiers dans ce partage. Il est donc nécessaire d’utiliser un vrai client WebDAV.

Sous MacOS X

Ouvrez un finder, cliquez sur le menu “Aller” > “Se connecter à un serveur distant” (cmd + K). Une petite boîte de dialogue, vous demandera l’adresse. Tapez l’adresse du votre serveur. Il vous demandera le login et le mot de passe de l’utilisateur (.webdav.passwd). Si l’authentification, c’est bien passé vous avez un nouveau dossier dans votre finder. Voilà, vous pouvez partager des fichiers.

Sous Gnome (Ubuntu)

C’est très simple: dans le menu Raccourcis, cliquez sur “Se connecter à un serveur…”

assistant windows 1

Sous Windows XP

Ouvrez les favoris réseaux. Cliquez sur “Ajouter un Favori réseau” sur le menu de gauche. une fenêtre s’ouvre.

assistant windows 1

Séléctionnez le premier choix et faite suivant.

assistant windows 2

Rentrez l’adresse dans le champs comme sur l’image ci-dessus.

assistant windows 3

Acceptez le certificat.

assistant windows 4

Saississez votre login et votre mot de passe.

assistant windows 5

Entrez un nom (celui que vous voulez ou laissez le nom par défaut).
Il est possible que l’acceptation du certificat vous soit souvent demandée tout comme que votre login/mot de passe.

FAQ

Mon serveur semble ne pas marcher à l’extérieur de mon réseau local.

Vérifiez bien la configuration de votre routeur. Les connexions entrantes sur le port 443 (https) doivent être redirigées vers votre serveur.

Je n’arrive pas à uploader des fichiers.

C’est probablement un problème de droit en écriture sur le serveur. Apache doit pouvoir écrire dans le répertoire de partage choisi. (chmod g+w et chown user:www-data)

Plus d’informations

JFreeChart dans vos applications Java

Bonjour, ce petit tutorial va tenter de vous expliquer comment faire de jolie diagramme dans une application JAVA/Swing.
Il est souvent agréable de montrer à ses utilisateurs un diagramme, un camembert ou bien un histogramme, plutôt qu’un gros tableau plein de chiffres. Il existe de nombreuses méthodes pour créer ce genre de graphique. Je vais vous présenter une méthode utilisant JFreeChart. JFreeChart est une bibliothèque java libre (malheuresement la documentation est payante). Elle est assez sexy et facile à utiliser.

Installation

Comme toutes les bibliothèques java, il faut télécharger le .jar et le placer dans un dossier de votre projet. Pour le téléchargement aller à la page [Download] et choississez la version qui correspond à votre système.

Décompressez le contenu de l’archive. Vous devriez obtenir une arborescence de fichier de la forme:

JFreeChart-*.*
    ant
    ChangeLog
    checkstyle
    docfiles
    experimental
    jfreechart-1.0.13-demo.jar
    lib
    licence-LGPL.txt
    maven-jfreechart-project.xml
    NEWS
    README.txt
    source
    swt
    tests

Ce qui est important, c’est le dossier lib. En effet, il contient les 3 archives jar nécessaire. À savoir: jfreechart-1.0.13.jar, jcommon-1.0.16.jar et iText-2.1.5.jar

Il faut en premier lier, ces jars avec votre projet java. La première étape est de copier les jars dans le répertoire principal de votre projet. Ensuite, dans eclipse faite un click droit sur votre projet, choississez : Properties. Sélectionnez Java Build Path puis l’onglet libraries

Appuyer sur Add External JARs… et sélectionnez les 3 jars de la JFreeChart que nous avons déplacés. Appuyer sur Ok

Normalement une partie “Referenced Libraries” s’ajoute à l’arborescence de votre projet. Ainsi eclipse inclura jfreechart à la compilation de votre projet.

Création du panel d’affichage des diagrammes.

Ce n’est pas le sujet de ce tutorial donc je ne vais pas m’attarder dessus. Les charts sont tous contenu dans un JPanel. Il suffit donc de créer un JPanel avec un layout adéquat pour mettre en place votre disposition. N’oubliez pas d’encapsuler votre panel dans un JScrollPane.

Premier Diagramme

JFreeChart permet de créer une multitude de diagramme, je ne traiterais que des PieCharts pour le moment. La première chose à faire est de construire un ensemble de valeurs: Pour un PieChart (camenbert), utilisez [DefaultPieDataset], c’est une interface simple et pratique pour stocker des paires valeur/clé. Pour un histogramme, utilisez plutôt une implémentation de [CategoryDataset]

.

DefaultPieDataset union = new DefaultPieDataset();
//remplir l'ensemble
union.setValue("Pierre",20.0);
union.setValue("Marie",20.0);
union.setValue("Jean",20.0);
union.setValue("Hime",20.0);
union.setValue("Sarah",20.0);

Il est tout à fait possible de faire une boucle for/while pour parcourrir un ensemble de données pour remplir celui du pieChart. Vous n’êtes pas tenu de remplir l’ensemble avant de créer le chart. Si vous ajoutez des valeurs dans l’ensemble après coup, le chart sera automatiquement mis à jour.

Pour créer le diagramme lui même, il suffit de faire appel à l'”usine à diagramme” [pattern factory].

JFreeChart repart = 
    ChartFactory.createPieChart3D("Répartition par personne",
    union, true, true, false);
ChartPanel crepart = new ChartPanel(repart);
add(crepart);

Le premier paramètre est, bien sûr, le titre, suivit de l’ensemble de valeurs. Les valeurs booléennes qui suivent sont respectivement : l’affichage de la légende, l’affichage d’un tooltips et la création d’une URL). Une fois le JFreeChart créé, vous devez récuperér l’encapsuler dans un ChartPanel et ajouter ce dernier dans votre Interface Homme Machine (IHM).

Aller plus loin

Personnaliser les couleurs de chaque valeur

Par défaut, JFreeChart utilise des couleurs aléatoire pour coloriser les éléments. Il existe un moyen pour forcer l’utilisation d’une couleur. On reprends l’exemple du dessus et on le modifie un petit peu pour modifier les couleurs

JFreeChart repart= 
    ChartFactory.createPieChart3D("Répartition par personne",
    union, true, true, false);
ChartPanel crepart = new ChartPanel(repart);
plot = repart.getPlot();
((PiePlot)plot).setSectionPaint("Pierre", new Color(255,0,0));
((PiePlot)plot).setSectionPaint("Marie", new Color(255,255,0));
((PiePlot)plot).setSectionPaint("Jean", new Color(255,0,255));
((PiePlot)plot).setSectionPaint("Hime", new Color(0,0,255));
((PiePlot)plot).setSectionPaint("Sarah", new Color(0,255,255));
add(crepart);

Pour modifier les couleurs, il faut récuperer une instance de Plot. Cela gère l’ensemble des règles de dessins. Dans chaque section, vous définissez la couleur à utiliser. Voici une capture d’écran du résultat final. Capture d'écran JFreeChart

Je mettrais à disposition le projet eclipse, d’ici quelques jours. En attendant, je donne le code source du panel principal:

import java.awt.Color;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.Plot;
import org.jfree.data.general.DefaultPieDataset;

public class Charts extends JPanel
{
    public Charts() 
    {
        super();
        DefaultPieDataset union = new DefaultPieDataset();
        union.setValue("Pierre",20.0);
        union.setValue("Marie",20.0);
        union.setValue("Jean",20.0);
        union.setValue("Hime",20.0);
        union.setValue("Sarah",20.0);
        JFreeChart repart = 
            ChartFactory.createPieChart3D("Répartition par personne",
            union,true, true, false);
        ChartPanel crepart = new ChartPanel(repart);
        Plot plot = repart.getPlot();
        ((PiePlot)plot).setSectionPaint("Pierre", new Color(255,0,0));
        ((PiePlot)plot).setSectionPaint("Marie", new Color(255,255,0));
        ((PiePlot)plot).setSectionPaint("Jean", new Color(255,0,255));
        ((PiePlot)plot).setSectionPaint("Hime", new Color(0,0,255));
        ((PiePlot)plot).setSectionPaint("Sarah", new Color(0,255,255));
        
        this.add(crepart);
    }
}

Plus d’Information

Qt4 et le design pattern Command

Bonjour,  ce petit tutorial va tenter de vous expliquer comment réaliser une opération longue tout en restant réactif dans une application Qt4.
Il existe plusieurs moyens mais je ne vais en décrire qu’un seul qui à mon sens est le plus propre. Comme cas pratique, j’ai choisi d’implémenter le Design patterns “Command”.
La première étape utilise des thread.

Communication entre un thread et une application Qt

Pas de solution miracle, pour faire “deux choses à la fois” dans une application, il faut passer par du multi-threading. Nous allons créer une classe thread qui hérite de QThread. Cette classe sera le support du traitement long à effectuer. Voyez ça comme une sorte encapsulation.

//.h de la classe

#ifndef THREAD_H
#define THREAD_H
#include <QThread>
#include "command.h"
class Thread : public QThread
{
    Q_ObJECT
        COMMAND* mycommand;
        bool undo;
public:

    Thread(COMMAND* mycommand,bool undo);

    protected:
        void run();
};

#endif // THREAD_H

Comme vous le voyez, c’est très simple. Nous héritons de QThread, nous avons deux membres dans cette classe: un pointeur vers une instance de la classe COMMAND (utile pour l’implémentation du patterns du même nom) et un booléen qui nous permet de déterminer le sens de l’action “annuler” (undo) ou “normal” (undo == false). bien entendu, il est possible d’avoir autant de paramètre que vous le souhaitez. Il ne faut pas oublié de redéfinir la fonction run().

// l’implémentation

#include "thread.h"

Thread::Thread(COMMAND* _mycommand,bool _undo)
        : mycommand(_mycommand),undo(_undo)
{

}
void Thread::run()
{
    if(undo)
        mycommand->undo();
    else
        mycommand->doCommand();
}

Dans le constructeur, je définis les données membres. La fonction run exécute la commande en fonction du paramètre undo. Il faut savoir que tout le code appelé dans run sera exécuté dans un thread différent.
À ce stade, nous avons une classe Thread qui est prête à recevoir et exécuter une “command”.

Nous allons voir maintenant comment créer un design pattern command.

Implémenter le design pattern command

Ce pattern est très utile pour gèrer l’annulation d’une action ou par exemple refaire la dernière action. Il consiste à créer une classe pour chaque action (du moins toutes les actions que vous voulez pouvoir modifier ou dans notre cas, exécuter dans un thread). Qt fournit des outils pour faire ça. Dans un cadre formateur, je préfère l’implémenter entièrement.
Il faut tout d’abord écrire la classe abstraite qui définit une commande. Cela permettra à notre classe thread de bien intéragir avec la commande.

#ifndef COMMAND_H
#define COMMAND_H
#include <QObject>
class COMMAND : public QObject
{
        Q_ObJECT

public:
    virtual void doCommand()=0;
    virtual void undo()=0;
signals:
        void Maximum(int M);
        void Minimum(int m);
        void valueChanged(int v);
        void done();
};

#endif // COMMAND_H

Il y a deux méthodes abstraites pures: l’une pour faire la commande, l’autre pour l’annuler. J’ai ajouté quelques signaux pour que la commande communique avec le thread principal pour informer l’utilisateur de l’avancée du la tâche en cours. Toutes les futures commandes de notre application doivent être des sous-classes de COMMAND. Vous l’avez deviné, il faut implémenter une commande, maintenant.
Notre commande sera vraiment basique, c’est une commande d’attente (so useless).

//wait.h

#ifndef WAIT_H
#define WAIT_H
#include "command.h"
class WAIT : public COMMAND
{
public:
    WAIT();

    virtual void doCommand();
    virtual void undo();

};

#endif // WAIT_H

Rien de particulier, juste la re-définition des fontions virtuelles pures. Voici leurs implémentations

#include "wait.h"
WAIT::WAIT()
{

}

void WAIT::doCommand()
{

int step = 10;
        emit Maximum(100);
        int i = 0;
        int k = 0;
        emit Minimum(i);
    for(int j = 0 ; j< 1000 ; j++)
    {
        sleep(0.5); //fake statement
        if(i>=step)
        {
                emit valueChanged(++k);
                i = 0;
         }
        i++;

    }
    emit valueChanged(++k);
    emit done();
}

void WAIT::undo()
{

}

Dans notre “doCommand”, nous calculons le pas de la notification de l’application principale. Ici, j’ai arbitrairement choisi 10 mais dans un contexte utile, le pas est égal à la taille de vos données à traiter divisé par le nombre de notification que vous voulez.
Nous émettons la valeur maximale. Initialisation des variables temporaires (i et k). On émet i (0). Nous faisons une bouble sur chaque élément à traiter, on fait le traitement et on calcule un peu pour savoir s’il faut ou pas prévenir l’application principale.
Il est bon de ne pas prévenir à chaque fois, car si vous travaillez sur plusieurs milliers ou millions de données le traitement des signaux ralentira un peu votre application. Comme exemple, imaginez que vous travaillez sur chaque pixel d’une grosse photo.

Il ne reste plus qu’a écrire la fenêtre principale qui affichera à l’utisateur l’avancée de notre traitement.

QProgressBar et QThread.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QtGui/QMainWindow>
#include <QProgressBar>
#include <QDockWidget>
#include "thread.h"
namespace Ui
{
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    QProgressBar *workinprogress;
    QDockWidget *Progressdock;
    Thread* myThread;
};

#endif // MAINWINDOW_H

Rien d’original, une mainwindow avec juste trois membres. Une QProgressBar qui affichera la progression.
Un DockWidget pour afficher la progesse bar, je ne l’ai pas implémenté dans cet exemple mais il peut être amusant d’afficher le dock quand une opération est en cours et la cacher quand c’est fini. Le dernier membre est une instance de notre classe Thread.

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "wait.h"



MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    workinprogress = new QProgressBar;
    Progressdock = new QDockWidget(tr("progress panel"));
    workinprogress->setValue(0);
    Progressdock->setWidget(workinprogress);
    Progressdock->setAllowedAreas(Qt::BottomDockWidgetArea);
    addDockWidget(Qt::BottomDockWidgetArea,Progressdock);
    WAIT* mywait = new WAIT();

    myThread = new Thread(mywait,false);
    connect(mywait,SIGNAL(Maximum(int)),workinprogress,SLOT(setMaximum(int)));
    connect(mywait,SIGNAL(Minimum(int)),workinprogress,SLOT(setMinimum(int)));
    connect(mywait,SIGNAL(valueChanged(int)),workinprogress,SLOT(setValue(int)));

    connect(ui->pushButton,SIGNAL(clicked()),myThread,SLOT(start()));

}

MainWindow::~MainWindow()
{
    delete ui;
}

Nous initialisons la QProgressbar et le QDockwidget. En suite, je paramètre un peu nos deux instances. Je crée alors une instance de WAIT et j’initialise le thread avec en paramètre l’adresse de notre commande.
Je connecte maintenant les signaux de la commande au slot de la QProgressBar.
Finalement, je connecte le clique sur “pushButton” sur le démarrage du Thread.
Ainsi, à chaque clique, il demarrera la commande wait.

Aller plus loin

Il serait préférable de créer une instance de WAIT à chaque clique et de l’ajouter dans une pile (dans la mainwindow). Cela est nécessaire pour finir le design pattern command. En haut de la pile, se trouve la dernière commande, si elle est annulée alors il faut la dépiler et exécuter undo().

Je proposerai en téléchargement ce petit exemple, d’ici quelques jours. En attendant, une petite capture d’écran. Capture d'écran Design Pattern Command, QThread et Qt.

Utiliser TagLib dans vos applications

Introduction

TagLib est une bibliothèque open-source écrite en C++ qui permet la lecture, l’écriture et la manipulation de Tags (étiquettes) de fichiers sons (Mp3, FLAC, MPC, Speex, WavPack and TrueAudio).
Ce tutorial doit vous donner les bases pour utiliser TagLib dans vos applications.

Installer TagLib

La première étape pour utiliser TagLib est bien sûr de l’installer sur son systême. Pour de nombreuses distributions GNU/Linux, TagLib existe dans le gestionnaire de paquets. Il est très important d’installer la bibliothèque ainsi que ses en-têtes (souvent un paquet avec un suffixe -dev ou -devel).

Sous Ubuntu 8.04:

sudo apt-get install libtag1c2a libtag1-dev

Bien sûr, vous pouvez compiler vous-même la bibliothèque. En téléchargeant le code source sur le site:

TagLib 1.5Pour les utilisateurs de Windows, il existe deux possibilités:

Télécharger et compiler les sources

ici

Une version binaire de la bibliothèque est disponible

ici

.

Compiler avec TagLib

Pour des environnements linux, il suffit d’installer la bibliothèque et à l’édition des liens, ajouter

-ltag

à la ligne de compilation. Attention: il est obligatoire d’ajouter le chemin des includes dans le includepath.

#include <taglib/tag.h>

seul ne marchera pas.

Exemple d’un petit makefile:


all:main

main: main.o MP3_File.o
        g++ -Wall -g -o main main.o MP3_File.o -ltag

main.o: main.cpp
        g++ -Wall -g -c main.cpp

MP3_File.o:MP3_File.cpp MP3_File.h
        g++ -Wall -g -c MP3_File.cpp

Lire des tags

Dans ce chapitre, nous allons voir comment TagLib doit être utilisé pour lire des tags. La bibliothèque est entièrement contrôlée par la classe

TagLib::FileRef

(Design pattern: Façade). L’initialisation commence par la création d’une instance

TagLib::FileRef

. Il faut ensuite la lier directement avec un fichier audio.


#include <tagli/tag.h>
#include <taglib/audioproperties.h>


 myTaggger = new TagLib::FileRef(filename);//filename est un char* contenant l'adresse du fichier
TagLib::String artist = myTaggger->tag()->artist ();

Comme vous le voyez, depuis l’objet FileRef, on appelle tag(). Pour ensuite appeler la fonction de la donnée désirée. Ici le nom de l’interprète de la chanson. Pour plus d’information voir

TagLib API documentation

).

Le format de chaîne de caractères renvoyé par TagLib est un format “à leur sauce” (TagLib::String) pour la conversion vers des formats de chaînes plus courrant voir FAQ.

Écrire des tags

L’écriture de tag avec TagLib est l’exacte réciproque de la lecture. En effet, la bibliothèque fournit des fonctions prennant en paramètre une chaîne de caractères.


#include <taglib/tag.h>
#include <taglib/audioproperties.h>


myTaggger = new TagLib::FileRef("chemin_du_mp3.mp3");

myTaggger->tag()->setTitle(TagLib::String("9ème Symphonie"),TagLib::String::UTF8);

myTaggger->save();

Il y a principalement 3 étapes :

  • créer une instance de TagLib::FileRef liée à un fichier.
  • Modifier les tags souhaités.
  • Sauvegarder les changements

Accès aux propriétés audio

Certaines informations comme le “bitrate” et la durée du fichier son ne sont pas contenu dans des tags. Il caractérise plus le flux audio que la chanson. Les auteurs de TagLib appellent ce genre de données des propriétés audio. Un petit exemple pour récupérer le bitrate.


#include <taglib/tag.h>
#include <taglib/audioproperties.h>


myTaggger = new TagLib::FileRef("chemin_du_mp3.mp3");
myTaggger->audioProperties()->bitrate();

Il est également possible de récuperer la longueur en milliseconde par l’appel à “audioProperties()->length()”

Conclusion

Ce tutorial vous a montré comment utiliser la bibliothèque

TagLib

. Ce tutorial ne couvre bien sûr pas toutes les fonctionnées que peut fournir cette bibliothèque. En ce qui conserne les exemples de ce tutorial, c’est à vous de créer l’architecture de votre application et d’intégrer les exemples au bon endroit.(renseignez vous sur le design pattern : adapter)

Personnellement, je l’utilise pour lire et modifier les tags de tous les formats excepté les mp3 car je trouve id3lib plus complète pour le mp3.

Utiliser Id3lib dans vos applications

Installer id3lib

La première étape pour utiliser id3lib est bien sûr de l’installer sur son systême. Pour de nombreuses distributions GNU/Linux, Il existe dans le gestionnaire de paquets, un paquet d’id3lib. Il est très important d’installer la bibliothèque ainsi que ses en-têtes (souvent un paquet avec un suffixe -dev ou -devel).

Sous Ubuntu 8.04:

sudo apt-get install libid3-3.8.3c2a libid3-3.8.3-dev

Sous fedora 9:

yum install id3lib-3.8.3-20.fc9 id3lib-devel-3.8.3-20.fc9

Bien sûr, vous pouvez compiler vous-même la bibliothèque. En téléchargeant le code source sur le site:

DownloadPour les utilisateurs de Windows, il existe deux possibilités:

Si vous utilisez Visual Studio, alors télécharger

ici

la version binaire de la bibliothèque. Ajoutez la, dans la liste des dépendences de votre projet et tout ira bien.

Si vous utilisez le compilateur libre mingw. Je vous conseille alors d’utiliser cette version de la bibliothèque. Sinon, il ne vous restera qu’à la compiler.

Compiler avec id3lib

Pour des environnements linux, il suffit d’installer la bibliothèque et d’ajouter

-lid3

à la ligne d’édition des liens.

Exemple d’un petit makefile:


all:main

main: main.o MP3_File.o
        g++ -Wall -g -o main main.o MP3_File.o -lid3

main.o: main.cpp
        g++ -Wall -g -c main.cpp

MP3_File.o:MP3_File.cpp MP3_File.h
        g++ -Wall -g -c MP3_File.cpp

Pour windows, le principe est le même.
Si vous utilisez visual studio. Modifier les paramètres de votre projet. Si vous utilisez mingw (gcc). Il sera surêment nécessaire de donner en paramètre l’emplacement de la bibliothèque et de ses en-têtes:"-I"lib\include".

Lire des tags

Dans ce chapitre, nous allons voir comment Id3lib doit être utilisé pour la lecture de tags. La bibliothèque est entièrement contrôlée par la classe

ID3_Tag

(Design pattern: Façade) L’initialisation commence par la création d’une instance

ID3_Tag

puis il faut la lier à un fichier mp3.


#include <id3/tag.h>

ID3_Tag mytag;
mytag.Link("chemin_du_mp3.mp3",ID3TT_ALL);
ID3_Frame* myFrame = NULL;
myFrame= myTag.Find(ID3FID_TITLE);
if(myFrame!=0)
{
	char* title = new char[1024];
	myframe->Field(ID3FN_TEXT).Get(title,1024);
	cout << title << endl;
}

Ensuite, nous déclarons un pointeur sur une

ID3_Frame

initialisé à NULL. Nous demandons le titre de mp3 par l’appel de la fonction Find(ID3_FrameID). Cette fonction prend en paramètre une valeur d’une énumération (pour connaitre toutes les valeurs de l’énumeration: voir

Id3lib API documentation

).

Si la frame n’est pas vide alors nous créons un tableau de caractères. Et nous demandons à la frame de remplir ce tableau avec le champs ID3FN_TEXT. Un tag correspond à une frame et une frame stocke l’information sous plusieurs formes. Ainsi il est évident que le titre est une donnée textuelle. Alors que le genre de musique est une valeur entière.

Écrire des tags

Il existe deux méthodes pour ajouter/modifier des tags. La première est l’inverse de la lecture. Elle nécessite la création et l’initialisation d’une

ID3_FRAME

puis l’ajout de cette frame à une instance de

ID3_Tag

. Cette méthode est longue et compliquée. C’est pourquoi, Id3lib fournit des méthodes plus simple d’utilisation


#include <id3/tag.h>
#include <id3/misc_support.h>


ID3_Tag mytag;
mytag.Link("chemin_du_mp3.mp3",ID3TT_ALL);
char* nouveautitre = new char[100];
sprintf(nouveautitre,"9eme symphonie");
ID3_AddTitle (&mytag, nouveautitre, true);
mytag->Update();

Comme toujours, vous devez créer et initialiser une instance de

ID3_Tag

. Puis, faite appel à la fonction ID3_AddTitle(). Cette fonction prend 3 paramètres: un pointeur sur un

ID3_Tag

pour identifier quel fichier doit être modifié, un tableau de caractères contenant la nouvelle valeur et un booléen, true pour écraser si le tag existe déja et false pour ne rien faire si le tag existe déja.

Accès aux headers

Certaines informations comme le “bitrate” et la durée du mp3 ne sont pas contenu dans des frames. Il existe bien une frame “Time” mais elle est rarement remplie. Ainsi, il vaut mieux utiliser les informations calculées dans les headers. Elles sont plus justes. Voici la liste des 4 champs principaux d’une instance Mp3_Headerinfo:


bitrate = m_mp3header->bitrate;
bitrate_si_variable = m_mp3header->vbr_bitrate;
frequence = m_mp3header->frequency;
durée   = m_mp3header->time;

Un petit exemple pour récupérer le bitrate.


#include <id3/tag.h>
ID3_Tag* mytag = new ID3_Tag;
mytag->Link("chemin_du_mp3.mp3",ID3TT_ALL);
Mp3_Headerinfo* header = mytag->GetMp3HeaderInfo();

if((header != NULL)&&(header->bitrate>0))
fields->Bitrate = header->bitrate;
else if(header != NULL)
fields->Bitrate = header->vbr_bitrate;

Il existe d’autres champs. Voici un exemple de transformation de ces champs en données lisible pour l’homme.


szMpegLayer = new char[10];
//MPEG layer
switch(m_mp3header->layer)
{
case MPEGLAYER_UNDEFINED: sprintf(szMpegLayer, "UNDEFINED"); break;
case MPEGLAYER_III:       sprintf(szMpegLayer, "Layer III"); break;
case MPEGLAYER_II:        sprintf(szMpegLayer, "Layer II");  break;
case MPEGLAYER_I:         sprintf(szMpegLayer, "Layer I");   break;
default:                  szMpegLayer = 0;
}

// MPEG Version 
szMpegVersion = new char[10];
switch(m_mp3header->version)
{
case MPEGVERSION_2_5: sprintf(szMpegVersion, "MPEG 2.5"); break;
case MPEGVERSION_2:   sprintf(szMpegVersion, "MPEG 2");   break;
case MPEGVERSION_1:   sprintf(szMpegVersion, "MPEG 1");   break;
default:              szMpegVersion = 0;
}

// Channel Mode
szChannelMode = new char[15];
switch(m_mp3header->channelmode)
{
case MP3CHANNELMODE_STEREO:         sprintf(szChannelMode, "Stereo");         break;
case MP3CHANNELMODE_JOINT_STEREO:   sprintf(szChannelMode, "Joint Stereo");   break;
case MP3CHANNELMODE_DUAL_CHANNEL:   sprintf(szChannelMode, "Dual Channel");   break;
case MP3CHANNELMODE_SINGLE_CHANNEL: sprintf(szChannelMode, "Single Channel"); break;
default:                            szChannelMode = 0;
}

Conclusion

Ce tutorial vous a montré comment utiliser la bibliothèque

id3lib

. Ce tutorial ne couvre bien sûr pas toutes les fonctionnées que peut fournir cette bibliothèque. N’hesiter pas à consulter le code source (et surtout les fichiers .h) d’id3lib pour l’utiliser au mieux.

La documention d’id3lib est dépassée mais elle peut vous être utile, notament les différents manuels.

En ce qui conserne les exemples de ce tutorial, c’est t’a vous de créer l’architecture de votre application et d’intégrer les exemples au bon endroit.

(renseignez vous sur le design pattern : adapter)

Écrire un applet Gnome2

Écrire un applet Gnome2 – Programmation

par Andrew Burton traduit par Renaud Guezennec

Historique
Révision 1.1 6 septembre 2007 RG
Ajout d’une copie de makefile et traduction française V0.5.
Révision 1.0 20 Decembre 2005 ADB
Ajout du lien pour télécharger l’applet.
Revision 0.02 15 Avril 2004 ADB
Version basé sur les retours de la liste de diffution: gnome-doc-list mailing. Utilisation de Docbook 4.2, amélioration de la section sur la compilation, Utilisation apropriée des marqueurs pour la FAQ, Modification du code.
Revision 0.01 13 Avril 2004 ADB
Version initiale.

Mise en bouche

Les applets Gnome sont de petites applications qui s’intègrent à Gnome. Elles fournissent des fonctionnalités simples et utiles pour l’utilisateur. Il y a quelques différences avec l’écriture d’une application Gnome normale. Le but de ce tutorial est d’expliquer; comment créer un petit applet.


Table des matières

Qu’est-ce qu’un Applet?
Construire l’infrastructure
Le rendre intéressant
Création d’un menu contextuel
Foire aux Questions
Conclusion
plus informations

Qu’est-ce qu’un Applet?

Dans Gnome, un applet est une petite application destinée à s’intégrer au tableau de bord de Gnome, donnant un accès rapide et facile sur un contrôle, comme un contrôleur de volume, un indicateur d’activité réseau, ou encore une information météorologique.

Les applets nécessitent la bibliothèque “libpanel-applet” pour s’exécuter et si vous souhaitez en développer un, vous aurez besoin d’installer le paquet de développement (souvent distinguer par -dev ou -devel en fin, cela dépend de votre distribution). En raison de leur symbiose avec Gnome, ils sont souvent moins complexes et plus facile à maîtriser pour un programmeur débutant dans l’environnement Gnome.

Après une installation de Gnome, sur un ordinateur de bureau, vous aurez la date et un applet de contrôle du volume dans le coin supérieur droit. Sur un ordinateur portable, vous trouverez aussi une barre d’état de votre batterie.

screenshot

Construire l’infrastructure

Sur un plan technique, Les applets sont des contrôles “Bonobo” intégrés au tableau de bord de Gnome. Cela signifie qu’il y a plusieurs différences avec un programme Gnome classique. La première différence est que chaque applet nécessite un fichier avec l’extension ‘.server’, qui contient la description pour le rendre compréhensible par “Bonobo”. Si vous ne comprenez pas très bien ceci ne vous inquiétez pas. La seule chose que le développeur a à faire est d’éditer le fichier, et remplacer certains champs par les spécificités de son applet.

Voici un exemple d’un fichier “.server” appellé “sample.server”.

Example 1. Un exemple de fichier .server

<oaf_info>
<oaf_server iid="OAFIID:ExampleApplet_Factory" type="exe"
location="/usr/lib/gnome-panel/myexample">
<oaf_attribute name="repo_ids" type="stringv">
<item value="IDL:Bonobo/GenericFactory:1.0"/>
<item value="IDL:Bonobo/Unknown:1.0"/>
</oaf_attribute>
<oaf_attribute name="name" type="string" value="Example Applet Factory"/>
<oaf_attribute name="description" type="string" 
value="Factory to create the example applet"/>
</oaf_server>
<oaf_server iid="OAFIID:ExampleApplet" type="factory"
location="OAFIID:ExampleApplet_Factory">
<oaf_attribute name="repo_ids" type="stringv">
<item value="IDL:GNOME/Vertigo/PanelAppletShell:1.0"/>
<item value="IDL:Bonobo/Control:1.0"/>
<item value="IDL:Bonobo/Unknown:1.0"/>
</oaf_attribute>
<oaf_attribute name="name" type="string" value="Example Applet"/>
<oaf_attribute name="description" type="string" value="An example applet"/>
<oaf_attribute name="panel:category" type="string" value="Amusements"/>
<oaf_attribute name="panel:icon" type="string" value="myicon.png"/>
</oaf_server>
</oaf_info>

Il y a quelques trucs à noter. Premièrement, il faut définir l’emplacement de l’exécutable, définie dans l’attribut “location” de oaf_server, N’oublier pas d’indiquer le type en “exe”. Dans cet exemple, notre fichier exécutable s’appelle myexample et est placé dans /usr/lib/gnome-panel/ . (Emplacement traditionnel de tous les applets) Secondement, nous définissons le nom de notre ‘applet Factory’ , ExampleApplet_Factory. Nommer votre .serveur et placer le dans /usr/lib/bonobo/servers/.

Après avoir ajouter le .server dans le dossier, nous pouvons commencer à écrire le code source du notre applet. Voici, un exemple simple: un applet “Hello World”.

Exemple 2. Hello World!

#include <string.h>
#include <panel-applet.h>
#include <gtk/gtklabel.h>
static gboolean
myexample_applet_fill (PanelApplet *applet,
const gchar *iid,
gpointer data)
{
GtkWidget *label;
if (strcmp (iid, "OAFIID:ExampleApplet") != 0)
return FALSE;
label = gtk_label_new ("Hello World");
gtk_container_add (GTK_CONTAINER (applet), label);
gtk_widget_show_all (GTK_WIDGET (applet));
return TRUE;
}
PANEL_APPLET_BONOBO_FACTORY ("OAFIID:ExampleApplet_Factory",
PANEL_TYPE_APPLET,
"The Hello World Applet",
"0",
myexample_applet_fill,
NULL);

La compilation ce fait avec cette commande:

bash~$ gcc $(pkg-config --cflags --libs libpanelapplet-2.0) -o myexample my_applet.cPour un Makefile, voici mon exemple:

PKGCONFIG = /usr/bin/pkg-config
CFLAGS = $(shell $(PKGCONFIG) –cflags libpanelapplet-2.0)
LDFLAGS = $(shell $(PKGCONFIG) –libs libpanelapplet-2.0)
OPTION = -g -Wall

all:myexample
myexample: my_applet.c
gcc $(OPTION) $(CFLAGS) $(LDFLAGS) -o myexample my_applet.cinstall:myexample sample.server
cp myexample /usr/lib/gnome-applets/
cp sample.server /usr/lib/bonobo/servers/
clean:
rm /usr/lib/gnome-applets/myexampleNoter que la variable d’environnement PKG_CONFIG_PATH doit contenir le chemin vers libpanelapplet-2.0.pc. Si vous obtenez l’erreur suivante:

Package libpanelapplet-2.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `libpanelapplet-2.0.pc'
to the PKG_CONFIG_PATH environment variable
No package 'libpanelapplet-2.0' found

Vous avez besoin d’exécuter les commandes suivantes:

bash$ PKG_CONFIG_PATH=/usr/lib/pkgconfig
bash$ export $PKG_CONFIG_PATH

Placer l’exécutable dans le répertoire /usr/lib/gnome-panel/ (souvenez-vous que le fichier .server doit être défini). Notre applet sera représenté (dans la fenêtre d’ajout d’applet) par l’icone myicon.png, qui doit être placé dans /usr/share/pixmaps/.

Nous ajoutons notre applet au tableau de bord Gnome par un clique droit sur la barre de Gnome, et choisissez “ajouter au tableau de bord…” dans la rubrique “Amusements”: Example Applet.

Comment Gnome fait pour lier le code C et le fichier .server? Le lien se fait grâce a l’appel de la fonction PANEL_APPLET_BONOBO_FACTORY. Cet appel utilise un nombre important de paramètres, et le prototype de la fonction est:

PANEL_APPLET_BONOBO_FACTORY (iid, type, name, version, callback, data)

Le premier paramètre spécifie le OAFIID, c’est l’identifiant pour Bonobo, et il devrait être le nom que vous avez défini dans le fichier .server, “ExampleApplet_Factory”. Le deuxième paramètre définit le type; pour un applet donc PANEL_TYPE_APPLET. Le troisième paramètre est le nom qui s’affichera lorsque vous exécuterez l’interface Bonobo. Le quatrième est le version. Nous devons aussi donner la fonction à exécuter,La fonction d’entrée dans notre code source est myexample_applet_fill(). Pour le dernier paramètre, nous spécifions l’envoi à la méthode d’entrée n’importe quel type de données. Dans notre exemple,nous ne passons rien ainsi nous mettons “NULL” comme valeur de paramètre.

Dans notre code, la définition de la méthode pour myexample_applet_fill () est:

myexample_applet_fill (applet, iid, data)

Noter que le nom de cette méthode doit être présent dans la définition de la “factory”.

Premièrement, nous testons que l’iid corresponde avec l’iid passé en paramètre. Si ce n’est pas le cas, nous annulons la création de l’applet, dans les autres cas, nous continuons avec le reste de la méthode.

if (strcmp (iid, "OAFIID:ExampleApplet") != 0)
return FALSE;

Il est préférable pour la fonction “main” qu’elle n’aie pas beaucoup de fonctionnalités. Assurez-vous que le OAFIID corresponde avec l’identifiant de Bonobo. Dessiner un ‘label’ dans l’applet, et afficher le. Facile mais pas vraiment utile. Après avoir fait tout cela, notre applet existe. Si vous faites un clique droit dessus, vous avez trois possibilités : Enlever l’applet, le déplacer et le fixer.

Le rendre intéressant

Nous allons changer le ‘widget’ avec le texte “Hello World” par un petit image. D’abord ajoutons une “GtkImage” dans l’applet:

image = gtk_image_new_from_file ("/usr/share/pixmaps/mypicture.png");

Alors, les widget GtkImage ne peuvent recevoir d’évènement (c’est vrai) et ainsi ils ne peuvent pas réagir vis à vis d’un clique de souris, Nous avons besoin de mettre le GtkImage dans GtkEventBox:

event_box = gtk_event_box_new ();
gtk_container_add (GTK_CONTAINER (event_box), image);
g_signal_connect (G_OBJECT (event_box), "button_press_event",
G_CALLBACK (on_button_press),
image);

N’oublier pas de supprimer le code pour la création du label avec “Hello World”.

Maintenant, nous avons faire que l’applet réagisse quand nous cliquons sur l’icône du “tableau de bord”. Bien sûr, nous avons besoin d’une fonction qui intercepte le clique de souris:

Example 3. Traiter un clique de souris dans votre applet.

static gboolean
on_button_press (GtkWidget *event_box, GdkEventButton *event,
gpointer data)
{
static int window_shown;
static GtkWidget *window, *box, *image, *label;
/* Don't react to anything other than the left mouse button;
return FALSE so the event is passed to the default handler */
if (event->button != 1)
return FALSE;
if (!window_shown) {
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
box = GTK_BOX (gtk_vbox_new (TRUE, 12));
gtk_container_add (GTK_CONTAINER (window), box);
image = GTK_IMAGE (gtk_image_new_from_file ("/usr/share/pixmaps/mypicture.png"));
gtk_box_pack_start (GTK_BOX (box), image, TRUE, TRUE, 12);
label = gtk_label_new ("Hello World");
gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 12);
gtk_widget_show_all (window);
}
else
gtk_widget_hide (GTK_WIDGET (window));
window_shown = !window_shown;
return TRUE;
}

Dans la fonction on_button_press() ci-dessus, nous créons une nouvelle fenêtre avec un peu de texte. Quand nous cliquons sur le bouton la fenêtre s’affiche si vous recliquez, elle disparaît.

Içi la capture d’écran de la fenêtre affichée quand on clique sur l’applet avec le bouton gauche de la souris:

screenshort

Création d’un menu contextuel

Quand on clique avec le bouton droit sur l’icône d’un applet sur le tableau de bord, un menu par défaut s’affiche avec la possibilité de: supprimer l’applet, le déplacer ou le figer. Il est possible d’ajouter quelques options – un bouton d’aide, une fenêtre “à propos” et une fenêtre de préférences.

Pour créer un menu “pop-up”, nous définissons en premier lieu le menu lui même. Vous pouvez le faire avec le code suivant:

static const char Context_menu_xml [] =
"<popup name=\"button3\">\n"
" <menuitem name=\"Properties Item\" "
" verb=\"ExampleProperties\" "
" _label=\"_Preferences...\"\n"
" pixtype=\"stock\" "
" pixname=\"gtk-properties\"/>\n"
" <menuitem name=\"About Item\" "
" verb=\"ExampleAbout\" "
" _label=\"_About...\"\n"
" pixtype=\"stock\" "
" pixname=\"gnome-stock-about\"/>\n"
"</popup>\n";

ou dans un fichier, charger pendant l’exécution avec la fonction panel_applet_setup_menu_from_file (). Les valeurs utilisées ici devrait être simple à comprendre. Nous ajoutons 2 éléments au menu, le nom apparaîtra dans le menu après un clique droit avec une icône ‘stockée’, défini dans GtkStockItem (les Stock sont des éléments présent dans gnomes permettant une internationnalisation facile des applications).

En suite, nous définissons les actions graphiques Bonobo:

static const BonoboUIVerb myexample_menu_verbs [] = {
BONOBO_UI_VERB ("ExampleProperties", display_properties_dialog),
BONOBO_UI_VERB ("ExampleAbout", display_about_dialog),
BONOBO_UI_VERB_END
};

Ceci lie les actions avec leurs fonctions spécifiées ci-dessus, et exécute les fonctions. Autrement dit, quand l’utilisateur choisit “Préférences…” depuis le menu contextuel, votre applet entre dans la fonction display_properties_dialog ().

En fin, nous avons besoin de construire le menu, rassemblons ensemble ces deux étapes:

panel_applet_setup_menu (PANEL_APPLET (myexample->applet),
Context_menu_xml,
myexample_menu_verbs,
myexample);

Notons que le dernier paramètre est un pointeur, qui peut être utilisé dans la fonction de gestion d’un évènement.

Vos gestionnaires d’évènements ont le prototype suivant:

static void
myexample_applet_properties_dialog (BonoboUIComponent *uic,
struct MultiRes *applet) {
/* Construire la fenêtre des propriétes et l'afficher ici */
...
}

Foire aux questions

1. Comment débogguer mon applet ? J’utilise souvent des appels à printf () pour voir ce que fait mon code, mais je ne peux pas le faire avec un applet!
2. Comment débogguer mon applet ? J’utilise souvent gdb, comment l’utiliser?
3.Je n’ai pas d’icône pour mon applet, je ne peux dont pas l’inclure dans le .server. Je ne peux pas trouver mon applet dans la liste des applets disponibles quand j’essaie de l’ajouter à mon tableau de bord.
4.Mon applet n’est pas visible dans le menu d’ajout au tableau de bord.
1. Comment débogguer mon applet ? J’utilise souvent des appels à printf() pour voir ce que fait mon code, mais je ne peux pas le faire avec un applet!
Exécuter votre applet par la ligne de commande /usr/lib/gnome-applet/my_example, Ensuite ajouter le à votre “tableau de bord”, ainsi tous les appels vers les sorties standards seront visibles dans la console (une astuce de Glynn Foster).
2. Comment débogguer mon applet ? J’utilise souvent gdb, comment l’utiliser!
Exécuter votre applet par la ligne de commande gdb /usr/lib/gnome-applet/my_example, puis faites ‘run’ dans gdb. Ensuite, ajouter à votre “tableau de bord”, ainsi vous pouvez maintenant utiliser gdb comme vous en avait l’habitude.
3. Je n’ai pas d’icône pour mon applet, je ne peux donc pas l’inclure dans le .server. Je ne peux pas trouver mon applet dans la liste des applets disponibles quand j’essaie de l’ajouter à mon tableau de bord.
Les Applets nécessitent une icône pour être afficher dans la listes d’ajout.
4. Mon applet n’est pas visible dans le menu d’ajout au tableau de bord.
L’applet est installé dans /usr/local/ par défaut. Gnome le cherche dans /usr. Vous pouvais exécuter ./configure –prefix=/usr pour installer votre applet dans un autre répertoire. Vous aurez besoin de vous fermer la session Gnome et de la rouvrir pour que les changement soit pris en compte.

Conclusion

Créer un applet n’est pas difficile. Cependant, il peut être aussi complexe que vous le souhaitez. Il est parfois plus raisonnable de créer une application. Exemple: vous désirez ajouter plus de widgets, Utiliser Glade combiné avec libxml sera plus facile pour construire votre IHM(Interface Homme Machine).

Un avertissement important en ce qui concerne l’exemple employé dans ce tutorial. J’ai compilé l’applet par la ligne de commande par simplicité ; pour un vrai applet, employer un fichier makefile. Cela tient compte des particularités matérielles (comme l’emplacement de l’icône), la maintenance n’en sera que plus facile.

Plus d’Information

  • Télécharger l’applet d’exemple Voici l’applet créé dans ce tutorial. L’archive (.tar) inclut aussi les ‘makefiles’ appropriés pour configurer et installer votre applet.
  • Les applets Gnome sont disponible au téléchargement dans le CVS de gnome sous le répertoire gnome-applets.
  • Installer la documentation de la bibliothèque libpanel-applet2 donne une bonne aide (bien qu’incomplète) pour écrire des applets.
  • Voici un vieux tutorial pour réaliser des applets avec GTK1.0
    Le site des développer Gnome.
  • Version originale de ce tutorial: cliquez-ici.