rendez-vous sur ArraKISS
Archives ContactATOM
whoami@ybad.name
# find . -iname

    dwm

    Présentation

    dwm est un gestionnaire de fenêtres de type tiling (Gestionnaire de fenêtres en tuile). L’emplacement des fenêtres est automatique, et optimisé pour que vous n’ayez pas à vous préoccuper de les organiser. De plus, sachez que tout peut être réalisé au clavier, ce qui est un gain de temps non négligeable.

    Fidèle à la philosophie suckless, le programme est écrit en C, dans un code très propre et léger, qui assure rapidité et fiabilité. La configuration se déroule dans un fichier à la syntaxe simplifiée : le config.h dont nous parlerons ensuite. Il est donc accessible malgré les apparences. Un système de patches permet d’étendre les fonctionnalités de dwm.

    Mais avant de commencer, voici quelques aperçus (cliquer pour agrandir):

    Utilisation

    Par défaut, vous disposez par défaut de 9 vues, ou plutôt 9 étiquettes à attribuer aux fenêtres. Oubliez le paradigme habituel des espaces de travail : avec dwm, vous collerez des étiquettes (tags) sur les fenêtres, comme si vous leur donniez un label.

    Une fois l’habitude prise, vous comprendrez pourquoi dwm veut dire Dynamic window manager.

    Chaque petit chiffre correspond à une étiquette (ou tag), qui est affecté à une fenêtre. Vous donnez à chaque fenêtre une étiquette, allant de 1 à 9, pour ensuite afficher les fenêtres portant la même étiquette, ou les fenêtres portant les étiquettes 1 et 2, etc.

    À vous de choisir si vous souhaitez afficher les fenêtres qui ont l’étiquette 1, 3, ou bien 3 et 4, ou encore “net” et “video”… En gros, ça ne marche pas exactement comme un espace de travail, vous choisissez les fenêtres que vous voulez voir, et pour cela, ce n’est plus vous qui vous déplacez, c’est vous qui demandez aux fenêtres “HEP! viens par là!

    Concrètement, cela veut dire que lorsque votre “vue” commence à être trop chargée, qu’il y a trop de fenêtre, vous pouvez donner à certaines d’entre elles une autre étiquette. Cette autre étiquette, pous pourrez plus tard choisir de l’afficher. Maintenant, vous changez d’activité. Vous choisissez une nouvelle étiquette avec Alt+chiffre, et ouvrez de nouvelles fenêtres. Mais vous voudriez pouvoir revenir à l’ancienne vue rapidement, pour retrouver votre ancienne activité. Avec le raccourci Alt+Tab, vous affichez une nouvelle vue vide. Pour revenir à la précédente, il suffit de refaire Alt+Tab.

    En somme, une “vue” correspond à un arrangement particulier des fenêtres, une sélection de plusieurs étiquettes. Cette vue pourra être retrouvée à tout moment.

    Les raccourcis claviers

    Dwm a été pensé pour être entièrement piloté au clavier. Attention toutefois, ne pensez pas utiliser dwm en utilisant les tags comme de simples espaces de travail, ce serait passer à côté de l’utilité de dwm. Ainsi, vous aurez la plupart du temps plusieurs fenêtres ayant un tag particulier à la fois d’affichés. Essayez, une fois que vous y serez habitué, vous serez beaucoup plus efficaces.

    Voici un descriptif des raccourcis clavier par défaut. La touche Mod1 désigne la touche Alt.

    Attention Vous noterez que tous les raccourcis ne fonctionnent pas avec un clavier français classique (azerty). Nous y remédierons très rapidement, soyez rassuré! ☺

    De l’usage des étiquettes

    Je vais présenter ici une utilisation de dwm que je trouve extrêmement pratique : l’utilisation avancée des étiquettes.

    Rappelons tout d’abord que l’on peut alterner entre la vue actuelle et la vue précédente avec mod+TAB.

    À chaque fenêtre est attribuée une étiquette (tag). Afin de consulter/cacher une fenêtre, je ne me déplace pas dans son “tag” avec mod+chiffre, mais j’affiche les fenêtres ayant cette étiquette avec ctrl+mod+chiffre.

    Par contre, je peux créer une seconde “vue” en allant choisir d’autres fenêtres. En faisant mod+TAB, j’alterne rapidement entre les vues.

    Prenons un exemple. J’écris actuellement cette page dans un terminal ayant l’étiquette 1 :

    Je souhaite afficher la fenêtre de conversation qui a l’étiquette 3. Je tape alors mod+ctrl+3 :

    Désormais, je souhaite naviguer sur internet, mon navigateur a l’étiquette 2. Je tape alors mod+2

    Pour revenir à la vue précédente, qui contenait la fenêtre de discussion et le terminal où j’écris cette page (étiquettes 1 et 3), il me suffit de faire mod+TAB

    Pour retourner au navigateur, on refait mod+TAB.

    Installation

    Dwm est téléchargeable depuis le site officiel. Choisissez alors l’archive la plus récente. Le code est tellement soigné qu’il y a peu de dangers, et la compilation est très simple.

    Il est aussi possible de récupérer la dernière version en développement de dwm avec git :

    git clone https://git.suckless.org/dwm
    

    Vous obtenez alors un dossier contenant les sources dwm. Déplacez-vous dans ce dossier puis entrez make && make install.

    Si vous ne souhaitez pas installer les exécutables dans /usr/local/bin, vous pouvez toujours préciser le chemin du dossier de destination dans le fichier config.mk, à la ligne PREFIX =.

    Vous aurez besoin des bibliothèques x11 et xinerama (disponibles par défaut sous OpenBSD, paquets libx11-dev et libxinerama-dev à ajouter sous debian).

    Démarrer une session dwm

    Voyons comment démarrer une session dwm.

    Avec GDM

    Par défaut, gdm va lire le fichier /usr/share/xsession/dwm.desktop pour démarrer une session dwm. Cela n’est pas toujours pratique, surtout si plusieurs utilisateurs veulent utiliser des configurations de dwm qu’ils ont chacun compilés dans leur dossiers personnels.

    Une solution possible est de créer de nouveaux fichiers de démarrage sur le même modèle que dwm.desktop, en remplaçant ce qui est exécuté par un script écrit pas vos soins.

    Par exemple, créons une session pour l’utilisateur paskal (qui se reconnaîtra ☺). On va alors mettre dans un fichier /usr/share/xsession/dwm- paskal.desktop :

    [Desktop Entry]
    Encoding=UTF-8
    Name=Dwm-paskal
    Comment=Dynamic window manager
    Exec=/home/paskal/startdwm.sh
    Icon=dwm
    Type=XSession
    

    Et dans le dossier de paskal, on a créé le fichier /home/paskal/startdwm.sh

    #!/bin/sh
    # Lancement automatique de firefox
    firefox &;
    # Lancement de mon dwm perso.
    exec /home/paskal/dwm-6.0/dwm
    

    Profitez-en pour mettre dans ce script des commandes que vous voulez lancer automatiquement. Il faut juste penser à mettre un “&” à la fin de la ligne.

    Avec xenodm (XDM)

    Il faut juste ajouter une ligne “dwm” dans le fichier ~/.xsession. Ce fichier ressemblera donc à ça :

    #!/bin/sh
    . ~/.profile 
    xsetroot -solid steelblue &
    xset b off &
    xrdb -merge ~/.Xresources &
    sct 4500 1>/dev/null &
    numlockx &
    xidle -timeout 900 -program "/usr/X11R6/bin/xlock -mode space" &
    dunst &
    mpd &
    xbanish &
    slstatus &
    dwm
    

    Pensez à mettre des “&” en fin de chaque ligne pour ne pas bloquer le démarrage, sauf pour dwm à la fin ;).

    Configuration

    La configuration de dwm se déroule dans le fichier config.h. Ce dernier est créé après la première compilation : c’est une simple copie du fichier config.def.h, vous pouvez donc le faire avant la première compilation ;)

    Je vous invite à lire la documentation de suckless à ce sujet.

    Le fichier config.def.h est le fichier de configuration par défaut. Copiez-le en config.h, c’est alors ce fichier qui sera utilisé pour la configuration.

    exemple

    Vous pourrez trouver mon fichier de configuration de dwm ici : dwm-config.h.

    Voici les quelques éléments modifiés :

    appliquer un patch

    Vous pouvez ajouter toutes sortes de fonctionnalités à dwm, en ajoutant des patches. Le site officiel regorge d’informations à ce sujet, et la configuration de chaque patch est expliqué. De façon générale, pour appliquer un patch, il faudra faire ceci dans le dossier de dwm pour la version tarball :

    patch -p1 < chemin/vers/le/patch.diff
    

    Pour une version issue du dépôt git :

    git apply /chemin/vers/le/patch.diff
    

    Mais comment tu fais pour avoir le code des touches, ou les évènements de la souris?

    La réponse est simple. Lancez la commande xev en console. Un fenêtre blanche apparaît. Lorsque vous mettez la souris dedans, vous voyez apparaître tout un tas de message dans le terminal : ce sont les évènements qu’il détecte.

    Pour avoir le code d’une touche, tapez sur cette touche, vous verrez apparaître un message de ce type (appui sur le 0 du clavier, soit le à):

    Vous pouvez donc récupérer le code de la touche entre parenthèses, ici, ce sera XK_agrave.

    Notez que cela vaut aussi pour la souris, afin de récupérer le numéro du bouton cliqué, ou tout autre évènement.

    Changer la touche méta par défaut

    Par défaut, c’est la touche Alt (ou Mod1) qui sert à changer de fenêtres, lancer dmenu, cacher la barre… etc. Par souci de compatibilité avec d’autres logiciels, ou par habitude, il est possible de choisir n’importe quelle autre touche. Par exemple, on peut utiliser la touche “windows” (Mod4), qui ne sert jamais. Elle est reconnue par le code Mod4Mask. Alors, dans le config.h, on remplace la définition de MODKEY par la valeur souhaitée :

    /* key definitions */
    #define MODKEY Mod4Mask
    

    Règles pour les fenêtres

    Il est bon de lire la documentation officielle.

    Ici, vous allez apprendre à définir un comportement particulier selon la fenêtre. Par exemple, si je veux assigner l’étiquette “7” au programme gajim, il est possible de définir cette règle :

    static const Rule rules[] = {
    /* class instance title tags mask isfloating monitor */
    { "Gajim", NULL, NULL, 1 << 6, False, -1 },
    };
    

    Trouver class et title d’une fenêtre

    Pour récupérer les informations sur une fenêtre, tapez xprop dans une console. Votre curseur va changer de forme. Cliquez alors sur la fenêtre voulue. Vous verrez apparaître dans la console les informations sur la classe, le titre de la fenêtre…

    Voici ce que par exemple vous obtiendrez :

    WM_CLASS(STRING) = "Navigator", "Iceweasel"
    WM_ICON_NAME(STRING) = "Rendez-vous sur Arrakis : dwm - Iceweasel"
    _NET_WM_ICON_NAME(UTF8_STRING) = "Rendez-vous sur Arrakis : dwm -
    Iceweasel"
    WM_NAME(STRING) = "Rendez-vous sur Arrakis : dwm - Iceweasel"
    _NET_WM_NAME(UTF8_STRING) = "Rendez-vous sur Arrakis : dwm - Iceweasel"
    

    WM_CLASS donne la “class” de la fenêtre, et WM_NAME le “name” de la fenêtre.

    Notez que l’on peut donner à un terminal un titre précis. Par exemple, avec urxvt, c’est avec l’option “-T”. Avec st, c’est comme xterm, avec “-t”. On peut donc envoyer un terminal à l’étiquette 8, avec cette règle

    { “NULL”, NULL, “MonTerminal”, 1 << 7, False, -1 },
    

    Par contre, il faudra le lancer ainsi : st -t "MonTerminal". Ça peut être utile dans des scripts…

    Fenêtre flottante

    Vous l’aurez compris, si vous voulez que la fenêtre flotte, il faudra mettre True dans la colonne isfloating.

    Fenêtre à une étiquette précise

    Pour désigner le tag où l’on veut automatiquement assigner à une fenêtre, c’est un peu plus complexe.

    Changer la police

    La police peut maintenant être n’importe laquelle depuis la version 6.1. Il faut modifier les lignes suivantes du fichier config.h :

    static const char *fonts[]        = { "Hack:size=9" };
    static const char dmenufont[]     = "Hack:size=9";
    

    Bien sûr, mettez ce que vous préférez à la place de Hack.

    Définir vos raccourcis clavier

    Il est bien entendu possible d’exécuter n’importe quelle commande via un raccourci clavier.

    Méthode simple

    Dwm propose déja une fonction toute prête pour lancer n’importe quelle commande : SHCMD.

    /* helper for spawning shell commands in the pre dwm-5.0 fashion */
    #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
    

    Alors, vous pouvez définir n’importe quel raccourci clavier dans la section static Key keys[] = {.

    Pour passer à la chanson suivante de la liste de lecture de mpd, je lance la commande mpc next. Pour l’associer au raccourci ctrl+flèche_droite J’ajoute à la section Key keys :

    { ControlMask,    XK_Right,  spawn,    SHCMD("mpc next") },
    

    Autre exemple. J’ai envie de lancer rox lorsque j’appuie sur Mod4+Mod1+h, et couper le son lorsque j’appuie sur la touche multimédia de mon ordinateur. J’écrirais alors ces lignes suivantes :

    { 0,            0x1008ff12,    spawn,        SHCMD("amixer -q set Master toggle") },
    { MODKEY|Mod1Mask,  XK_h,        spawn,        SHCMD("rox") },
    

    Hé, mais c’est quoi ça, Mod4 et Mod1 ??? Ah oui, j’allais oublier. Mod4 désigne la touche Méta, souvent la touche “windows” située entre Fn et alt. Mod1 quand à lui, désigne la touche Alt.

    Autre méthode

    Il faut d’abord définir la commande à éxécuter, puis ensuite, on définira le raccourci.

    Les commandes sont définies à cet endroit du config.h, il y en a déja deux :

    /* commands */
    static const char *dmenucmd[] = { "dmenu_run", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
    static const char *termcmd[] = { "uxterm", NULL };
    

    La première ligne sert à lancer dmenu avec les couleurs de dwm. C’est en fait ce qui se passe lorsque vous tapez le raccourci Mod+P . dmenu est inclus dans le paquet dwm-tools ou suckless-tools sous debian.

    La deuxième ligne lance un terminal, c’est ce qui se passe lorsque vous faîtes Mod+Shift+Entrée. Vous pouvez modifier la commande uxterm, par votre terminal favori (xterm, urxvt, xfce4-terminal, lxterminal…).

    On va ajouter en-dessous de ces lignes nos propres fonctions!

    Par exemple, je voudrais ajouter deux raccourcis : l’un pour lancer gajim, l’autre pour couper/activer le son. Il faudra définir deux fonctions sur le même modèle que les précédentes. Donnez leur le nom que vous voulez, du moment que vous vous y retrouvez.

    static const char *gajim[] = { "gajim", NULL };
    static const char *muteson[] = { "amixer", "-q", "set", "Master", "toggle", NULL };
    

    Note : Remarquez que lorsque une commande contient des espaces, chaque argument doit être entre guillemets suivi d’une virgule.

    Les commandes finissent toujours par NULL.

    Bien, maintenant que nos fonctions sont définies, on va les associer à un raccourci clavier. Voici ce que ça donnera, dans la section des raccourcis claviers :

    static Key keys[] = {
    /*il y a d’autres choses avant….*/
    { MODKEY|Mod1, XK_i, spawn, {.v = gajim } },
    { 0, 0x1008ff12, spawn, {.v = muteson } },
    

    Quelques explications:

    Et pour la souris?

    Bien sûr, on peut reprendre le même schéma que pour le clavier. En fait, j’utilise pour ma part, une action personnalisée pour qu’un clic-droit sur la barre de status ou le fond d’écran, m’affiche un menu.

    Voici les étapes à suivre :

    On définit la commande du script. Je lui donne le petit nom menu, puisque ça me sert à afficher un menu via :

    static const char *menu[] = { "jgmenu", NULL }; 
    

    On fait en sorte que cette fonction soit appelée lorsque l’on clic droit sur la barre de status, et le fond d’écran :

    { ClkStatusText, 0, Button3, spawn, {.v = menu } }, 
    { ClkRootWin, 0, Button3, spawn, {.v = menu} },
    

    On peut aussi modifier les raccourcis déja existants. Si l’on souhaite que lorsqu’on clic-milieu sur le titre d’une fenêtre, ça la ferme :

    static Button buttons[] = {
    /* click event mask button function argument */
    { ClkWinTitle, 0, Button2, killclient, {0} },
    };
    

    Autre exemple, ici, faire tourner la molette de la souris sur le titre des fenêtres permet de les “faire tourner”. Très pratique lorsqu’on utilise le mode maximisé afin de changer facilement de fenêtres :

    { ClkWinTitle,        0,          Button4,      focusstack,     {.i = +1 } },
    { ClkWinTitle,        0,          Button5,      focusstack,     {.i = -1 } },
    

    Voila, rien de bien compliqué en définitive. On définit d’abord la commande à éxécuter, en lui donnant un nom de fonction au choix. Ensuite, on peut lancer cette commande avec spawn, suivi du nom de la fonction.

    Changer le volume sonore avec la molette de la souris

    Sur le même modèle que le paragraphe précédent, on peut augmenter/diminuer le volume sonore lorsque l’on fait rouler la molette de la souris sur la barre de status.

    Premièrement, lancez xev, et faîtes rouler la molette dedans sa fenêtre pour vois à quel bouton de la souris ça correspond (cela s’affiche dans la console). Chez moi, c’est les boutons 4 et 5.

    Et enfin, tout en bas, dans la section de la souris, après static Button buttons[] = { on indique les raccourcis, c’est à dire la molette sur la barre de status, avec la commande permettant de changer le son lancée avec SHCMD :

    { ClkStatusText,      0,          Button4,      spawn,    SHCMD("amixer -q set Master 2dB+ unmute") },
    { ClkStatusText,      0,          Button5,      spawn,    SHCMD("amixer -q set Master 2dB- unmute") },
    

    Dans cet exemple, c’est amixer qui permet de modifier le volume sonore sous Linux si vous n’utilisez pas pulseaudio. Une autre commande nommée mixerctl est disponible sous OpenBSD.

    Modifier la configuration pour les claviers français

    Les touches “chiffre”

    Malheureusement, dwm est configuré par défaut pour les claviers anglais. Les chiffres au dessus des lettres de votre clavier ne seront pas lus comme tels, mais comme étant un “&” pour le “1”, un “é” pour le “2”, un ““” pour le “3”… On va donc remédier à tout ça. Le code de nos touches se récupère très facilement avec xev. Il faut lancer xev en console, taper sur une touche, et lire ce qui est retourné.

    Remplaçons cette portion :

    TAGKEYS(                XK_1,                0)
    TAGKEYS(                XK_2,                1)
    TAGKEYS(                XK_3,                2)
    TAGKEYS(                XK_4,                3)
    TAGKEYS(                XK_5,                4)
    TAGKEYS(                XK_6,                5)
    TAGKEYS(                XK_7,                6)
    TAGKEYS(                XK_8,                7)
    TAGKEYS(                XK_9,                8)
    

    Par :

    TAGKEYS(                XK_ampersand,               0)
    TAGKEYS(                XK_eacute,                1)
    TAGKEYS(                XK_quotedbl,                2)
    TAGKEYS(                XK_apostrophe,              3)
    TAGKEYS(                XK_parenleft,               4)
    TAGKEYS(                XK_minus,                 5)
    TAGKEYS(                XK_egrave,                6)
    TAGKEYS(                XK_underscore,              7)
    TAGKEYS(                XK_ccedilla,                8)
    

    Ainsi que :

    { MODKEY,                 XK_0,    view,         {.ui = ~0 } },
    { MODKEY|ShiftMask,         XK_0,    tag,        {.ui = ~0 } },
    

    Par :

    { MODKEY,                 XK_agrave,    view,         {.ui = ~0 } },
    { MODKEY|ShiftMask,         XK_agrave,    tag,        {.ui = ~0 } },
    

    Pour changer d’écran

    Il faut françiser la touche “.” pour nos claviers. Donc, remplacer dans le config.h “period” par “semicolon”, car pour nous, c’est le point-virgule :

    { MODKEY, XK_comma, focusmon, {.i = -1 } },
    { MODKEY, XK_semicolon, focusmon, {.i = +1 } },
    { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
    { MODKEY|ShiftMask, XK_semicolon, tagmon, {.i = +1 } },
    

    Personnaliser la barre d’état

    Il est possible d’afficher ce que l’on veut dans la barre d’état. Cela se définit juste avant le lancement de dwm, donc selon les cas dans votre ~/.xsession ou autre. Dwm lira ce qui est passé en argument à la commande xsetroot. Cela donnera quelque chose comme ça :

    while true; do
    	xsetroot -name "$(date +"%F %R" )"
    	sleep 5 # Update time every 5 seconds
    done &
    dwm
    

    Ça affiche la date et l’heure, tout simplement.

    Notez que l’on peut faire de même avec des scripts plus compliqués ou en les écrivant en python, en C, en ce que vous voulez… Par exemple, ça donne :

    aperçu de dwmstatus

    En fait, vous pouvez afficher ce que vous souhaitez, du moment que vous passez ce texte à travers xsetroot.

    Il existe même un projet de lié à suckless.org pour faire ça en suivant la philosophie suckless : slstatus.

    Avec slstatus

    Il est possible de faire exactement la même chose, mais entièrement en C. Je vous laisse imaginer le gain en performance!

    Des fonctions toutes prêtes sont disponibles. Consultez le site : https://git.suckless.org/slstatus/file/README.html.

    Voici à quoi ressemble mon fichier de configuration de slstatus :

    static const struct arg args[] = {
    	/* function format        argument */
    	{ run_command, "%s ",          "~/bin/mpd-status" },
    	{ run_command, "[%s] ",        "~/bin/nbmail" },
    	{ disk_perc, "[%s%%] ",        "/" },
    	{ disk_perc, "[/home:%s%%] ",  "/home" },
    	{ datetime, "[%s]",            "%F %T" },
    };
    

    Les scripts mpd-status et nbmail.sh servent à afficher la chanson jouée par mpd et le nombre de nouveaux mails. Ils sont disponibles sur mon dépôt.

    Bonus pour les utilisateurs d’OpenBSD

    Si vous utilisez OpenBSD (vous avez bien raison ;)), sachez que dwm profite de “pledge” par défaut :)

    Conclusion

    Il y a un programme essentiel à utiliser dans dwm : j’ai nommé dmenu. Vous pourrez au fur et à mesure lire des exemples d’utilisation que je posterai ici, dans la catégorie dmenu.

    N’hésitez pas à me contacter pour toute précision, commentaire, ou astuces à ajouter.