cd / ; apropos ;
Table des matières

dwm : le guide à la prx #

Présentation #

Un gestionnaire de fenêtres est censé vous aider à GÉRER les fenêtres (sans blague ^^), pas vous ajouter du travail.

Si vous passez trop de temps à déplacer les fenêtres, les redimensionner, les changer encore un peu de place parce qu'elles se superposent, chercher la fenêtre dont vous avez besoin (...), alors dwm est fait pour vous : il s'occupera de ça à votre place.

dwm ne vient pas entraver votre activité, mais vous aide à être plus efficace.

C'est, de loin, mon gestionnaire de fenêtres favori. :)

dwm est souvent associé à dmenu, un tout petit outil qui sert de lanceur d'applications, et bien plus si on a un peu d'imagination.

Fidèle à la philosophie suckless, dwm 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 "config.h" suffisamment bien organisé pour le rendre accessible sans connaissances en C. Plusieurs patches permettent d'étendre les fonctionnalités de dwm de façon considérable selon vos envies.

Si vous êtes curieux, je vous invite à consulter la visite guidée avant de parcourir la suite de cette documentation:

Visite guidée de dwm

Site officiel de dwm

Site officiel pour dmenu

Installer/compiler dwm #

dwm se configure en éditant les sources. Il est donc inutile de l'installer via un gestionnaire de paquet : autant le compiler :).

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

Vous n'êtes pas obligés d'avoir les droits superutilisateur pour utiliser dwm : installez-le dans votre $HOME.

Voici quelques lignes qui permettent de:

ftp https://dl.suckless.org/dwm/dwm-6.2.tar.gz
tar xvzf dwm-6.2.tar.gz
cd dwm-6.2
sed -i /^#FREETYPEIN/s/^#// config.mk # facultatif
make
make install PREFIX=$HOME MANPREFIX=$HOME/man/
echo $PATH | grep -q $HOME/bin || echo 'PATH=$PATH:~/bin' >> $HOME/.profile

dwm est installé dans /home/vous/bin/dwm.

Vous pourrez alors lancer une session en ajoutant dans le fichier ''$HOME/.xsession'' ou ''$HOME/.xinitrc'' (selon votre cas) le chemin cité.

Voici un exemple qui permet d'afficher l'heure dans le status (commande ''xsetroot''), change par la même occasion la couleur du fond d'écran avant de lancer dwm :

while true; do xsetroot -name " $(date +"%H:%M") "; sleep 60; done &
xsetroot -solid steelblue &
$HOME/bin/dwm

Vous aurez remarqué que toutes les lignes sauf la dernière terminent par un "&" afin de ne pas bloquer le démarrage de la session.

Par la suite, vous serez amenés à modifier la liste des commandes lancées au début de votre session : dwm gère les fenêtres, et c'est tout!

Utilisation #

Clavier #

dwm privilégie la gestion des fenêtres au clavier. Des raccourcis bien pensés font gagner du temps sans avoir à se tordre les doigts ou les neurones.

La touche Mod1 désigne la touche Alt. On s'en servira beaucoup. On pourra changer pour autre chose si vous préférez. On y fera référence par MODKEY par la suite. :)

Par exemple, on aura :

Arrangement des fenêtres #

Par défaut, dwm va arranger vos fenêtres de la façon suivante :

 +-------------------+------+--------------------------------------+
 |                   |      |                             |        | 
 | 1 2 3 4 5 6 7 8 9 | mode | titre fenêtre active        | status |
 |                   |      |                             |        |
 +-------------------+------+------------+----------------+--------+
 |                                       |                         |
 |                                       |                         |
 |                                       |                         |
 |                                       |                         |
 |                                       |          stack          |
 |                                       |                         |
 |                                       |                         |
 |                                       |                         |
 |                master                 +-------------------------+
 |                                       |                         |
 |                                       |                         |
 |                                       |                         |
 |                                       |                         |
 |                                       |          stack          |
 |                                       |                         |
 |                                       |                         |
 |                                       |                         |
 +---------------------------------------+-------------------------+

On peut changer le mode d'arrangement des fenêtres avec les raccourcis suivants :

Vous pouvez passer rapidement d'un mode à un autre avec MODKEY-space ou en cliquant sur le symbole de l'arrangement (''[]='', ou ''[M]'' ou ''><>'').

MODKEY-shift-space passe la fenêtre courante en mode flottant ou la remet en tiling.

On pourra configurer de nouveaux modes plus tard si on le souhaite :)

Ouvrir/fermer/choisir des fenêtres #

Tags #

Vous disposez par défaut de 9 étiquettes à attribuer aux fenêtres. Essayez d'oublier le paradigme habituel des espaces de travail : avec dwm, vous collerez des étiquettes (tags) sur les fenêtres.

Chaque petit chiffre correspond à une étiquette (ou tag), qui est affecté à une fenêtre. Vous donnez aux fenêtre une ou plusieurs étiquette, allant de 1 à 9.

À 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.

Si vous changez d'activité, vous afficherez d'autres étiquettes et ouvrirez de nouvelles fenêtres.

Pour revenir à l'ancienne vue rapidement, appuyez sur MODKEY+Tab.

À chaque fois que vous appuyez sur MODKEY-Tab, vous alternez entre la vue actuelle et la précédente. C'est vraiment puissant!

Utiliser dwm en utilisant les tags comme de simples espaces de travail, bien que cela soit possible, serait passer à côté de l'utilité de dwm. Essayez, une fois que vous y serez habitué, vous serez beaucoup plus efficaces.

En résumé :

Multi-screen #

Puisque le "." n'est pas facilement accessible sur un clavier azerty, on pourra le remplacer par ";".

C'est absolument génial quand on vidéoprojette. :)

Et la souris ? #

dwm est tout à fait utilisable avec la souris, et peut même s'avérer plus pratique pour certains en ce qui concerne la gestion des étiquettes.

Vous pourrez déplacer une fenêtre en maintenant MODKEY et en cliquant sur une fenêtre avec le bouton gauche.

Pour la redimensionner, faîtes de même avec MODKEY et le bouton droit de la souris.

Vous pouvez afficher les fenêtres avec l'étiquette "n" en cliquant sur le chiffre correspondant :

Pour changer les étiquettes d'une fenêtre :

Cliquez sur le symbole du mode d'arrangement pour modifier ce dernier (tiling/floating).

Si vous faîtes un clic milieu sur le status, un terminal s'ouvre. Si vous faîtes un clic milieu sur le titre de la fenêtre, elle passe dans la zone principale.

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.

Je vous invite à lire la documentation de suckless:

https://dwm.suckless.org/customisation/

On va décortiquer ce config.h pour en comprendre les différentes sections. Vous allez voir, rien de très méchant.

Apparence #

La première partie permet de modifier l'apparence. Ne tenez pas compte du type de la variable ("static const unsigned int" par exemple) :

Viennent ensuite les couleurs. Elles sont tout d'abord définies avec des noms peu pratiques comme "col_gray1" ou "col_cyan". Ensuite, elles sont utilisées dans la variable ''*colors[][3]'' dans l'ordre suivant :

Tags #

On peut diminuer le nombre de tags ou bien changer leur nom en modifiant :

static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };

Par exemple, pour avoir 4 étiquettes avec des noms :

static const char *tags[] = { "web", "texte", "travail", "?" };

Règles pour les fenêtres #

Cette partie est totalement facultative, mais peut permettre de décider à l'avance quelles étiquettes attribuer à certaines fenêtres, voire même de les rendre flottantes d'emblée.

https://dwm.suckless.org/customisation/tagmask

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 },
};

Pour désigner le tag où à automatiquement assigner à une fenêtre, voilà ce qu'on peut comprendre :

Pour récupérer les informations sur une fenêtre (classe, nom..), entrez "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 désirées.

Voici ce que par exemple vous obtiendrez :

WM_CLASS(STRING) = "Navigator", "Firefox"
WM_ICON_NAME(STRING) = "tools | suckless.org software that sucks less - Mozilla Firefox"
_NET_WM_ICON_NAME(UTF8_STRING) = "tools | suckless.org software that sucks less - Mozilla Firefox"
WM_NAME(STRING) = "tools | suckless.org software that sucks less - Mozilla Firefox"
_NET_WM_NAME(UTF8_STRING) = "tools | suckless.org software that sucks less - Mozilla Firefox"

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

Par défaut, la configuration prévue place l'étiquette 9 sur Firefox :

{ "Firefox",  NULL,       NULL,       1 << 8,       0,           -1 },

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...

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

Modes d'arrangement #

Vient ensuite des options pour l'arrangement des fenêtres :

Ensuite, c'est la liste des arrangements disponibles. Leur ordre est important : le premier sera à l'index 0, le second au 1, puis le 2... C'est à avoir en tête lorsqu'on appellera la fonction "setlayout".

À chaque fois, un symbole précède le nom de l'arrangement pour le reconnaître rapidement.

Les modifieurs #

On arrive aux raccourcis, le coeur de dwm. On utilise très souvent une combinaisont utilisant MODKEY. Par défaut, c'est la touche Alt et 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

Quatre actions sont ensuite définies dans la macro "TAGKEYS". Chacune est accessible en appuyant sur un modifieur suivi du numéro de l'étiquette "[n]" :

Vous pouvez changer ces modifieurs si vous le souhaitez. Inverser "view" et "toggleview" ainsi que "tag" avec "toggletag" peut être intéressant.

Clavier #

Il est bien entendu possible d'exécuter n'importe quelle commande via un raccourci clavier, 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") },

Vous pouvez aussi définir de nouvelles commandes comme c'est déjà fait à 2 reprises dans le config.h, mais avouez que c'est se compliquer la vie pour rien ;) :

/* commands */
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
static const char *termcmd[]  = { "st", NULL };

La première ligne sert à lancer dmenu avec les couleurs de dwm. C'est en fait ce qui se passe lorsque vous appuyer sur MODKEY+p. Vous remarquerez que le nom des couleurs correspond à ceux donnés au début du fichier.

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 st, par votre terminal favori (xterm, urxvt, xfce4-terminal, lxterminal...).

Chaque raccourci clavier suit la syntaxe suivante :

{ Modifieur,       touche,      fonction,   {argument} },

Prenez note des éléments suivants pour éditer vos raccourcis claviers :

Obtenur le code des touches ou les évènements de la souris #

Lancez la commande "xev" en console. Un fenêtre blanche apparaît. Lorsque vous déplacez 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, appuyez sur cette touche, vous verrez apparaître un message de ce type (ici j'ai appuyé sur le "0" du clavier, soit le "à"):

 KeyPress event, serial 32, synthetic NO, window 0x2000001,
    root 0x664, subw 0x0, time 9156601, (1010,215), root:(1012,236),
    state 0x0, keycode 19 (keysym 0xe0, agrave), same_screen YES,
    XLookupString gives 2 bytes: (c3 a0) "à"
    XmbLookupString gives 2 bytes: (c3 a0) "à"
    XFilterEvent returns: False

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.

Raccourcis souris #

Bien sûr, on peut reprendre le même schéma que pour le clavier. Cela donne:

{ élément cliqué,      modifieur,    bouton de la souris,   fonction,  argument };

Par exemple, clic-droit sur la barre de status peut permettre de lancer "jgmenu" :

{ ClkStatusText,        0,              Button3,        spawn,          SHCMD("jgmenu_run") },

Pour un autre menu d'applications, il existe aussi xfce4-appfinder.

Plusieurs éléments sont "cliquables" :

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être :

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

Modifier la configuration pour les claviers français #

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 } },

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 } },

Exemple #

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

https://si3t.ch//misc/logiciel-libre/suckless/dwm/dwm-config.h

J'ai choisi d'intégrer quelques patches directement dans le config.h pour garder le code source le plus propre possible. Ces derniers sont peu nombreux, et me servent en vérité rarement car dwm répond par défaut à tous mes besoins.

Voici les quelques éléments modifiés/ajoutés :

https://github.com/phillbush/xmenu

#!/bin/sh

xmenu <<EOF | sh &
🌍 Web   firefox
≡ Apps  desktop
🐉 DGS   firefox "https://www.dragongoserver.net/"
📁 Fichiers  xfe
▶ Next  mpc next
= Toggle    mpc toggle
⏻ OFF   doas /sbin/shutdown -hp now
EOF

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ée. De façon générale, pour appliquer un patch, il faudra faire ceci dans le dossier de dwm pour la version tarball :

https://dwm.suckless.org/patches

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

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

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

Voici quelques patches que vous trouverez peut-être intéressants :

attachabove et attachbottom changent le comportement par défaut lorsqu'une nouvelle fenêtre s'ouvre. Elle est mise dans le stack plutôt que dans la zone master. En ce qui me concerne, si j'ouvre une fenêtre, c'est qu'elle m'intéresse donc l'avoir dans le master me parait pertinent, mais certaines trouveront peut-être ce comportement intrusif.

attachabove

attachbottom

noborder permet de cacher les bordures quand il n'y a qu'une fenêtre. Je préfère pour ma part savoir que j'ai bien le focus placé sur la fenêtre courante.

noborder

systray permet d'ajouter... un systray. Mais en avez-vous vraiment besoin? ;)

systray

focusmaster permet de sélectionner le master rapidement.

focusmaster

focusurgent fait de même avec une fenêtre urgente.

focusurgent

hide_vacant_tags cache les étiquettes sans fenêtres.

hide_vacant_tags

launchers ajoute un bouton pour lancer des applications.

launchers

leftstack place le master à droite.

leftstack

nametag permet de renommer les tags à tout instant.

nametag

push permet de déplacer une fenêtre d'une position à l'autre. Je trouve ça dommage de devoir s'en préoccuper, le gestionnaire de fenêtre ne devrait pas être source de distraction, mais si vous en avez le besoin il y a ce patch.

push

pertag permet d'avoir un layout différent par tag. C'est un gros patch qui entre souvent en conflit avec les autres.

pertag

resetnmaster permet de remettre rapidement à 1 ne nombre de fenêtres dans la zone master.

resetnmaster

Quelques modes d'arrangement intéressants :

bottomstack

gridmode

deck

N'hésitez pas à fouiller, soyez curieux :)

Le status #

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...

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.

slstatus

Des fonctions toutes prêtes y sont disponibles.

Enfin, je vous propose le script suivant qui permet de mettre à jour les informations seulement lorsque ledit script reçoit un signal.

#!/bin/sh
# set dwm's status when USR1 signal is received
#   pkill -USR1 statusloop
#   kill -USR1 $(cat /tmp/statusloop.lock)

LOCKFILE=/tmp/statusloop.lock

set_status()
{
    xsetroot -name " $(status) "
}

reload()
{
    kill -USR1 $(cat ${LOCKFILE})
}

if [ -e ${LOCKFILE} ]; then
    echo "already running, killing"
    kill -9 $(cat ${LOCKFILE})
fi

trap set_status USR1

# make sure the lockfile is removed when we exit
trap "rm -f ${LOCKFILE}; exit" INT QUIT TERM

echo $$ > ${LOCKFILE}

set_status

# update clock every minutes
(while true; do sleep 60; reload; done) &
# mpd changes
(while true; do mpc --wait current >/dev/null; reload; done) &

# global loop
while true; do sleep .1; done

Il appelle le script "status" lorsque le signal USR1 est reçu, qui peut être n'importe quoi mais qui pour moi sert à récupérer les informations que je veux afficher.

/code/status/

Ainsi, à chaque changement de chanson de mpd, c'est rechargé grâce à la ligne qui appelle ''mpc --wait''.

Cela me permet d'afficher le volume sonore dès qu'il est modifié.

Dans le config.h de dwm, j'ai fait en sorte qu'un signal USR1 soit envoyé à mon script grâce à la commande ''reload-dwm-status'', appelée dès que je modifie le son en faisant rouler la molette de la souris sur la barre :

{ ClkStatusText,        0,              Button4,        spawn,          SHCMD("sndioctl -q output.level=+0.1 && reload-dwm-status") },
{ ClkStatusText,        0,              Button5,        spawn,          SHCMD("sndioctl -q output.level=-0.1 && reload-dwm-status") },

Bonus pour les utilisateurs d'OpenBSD #

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

Autres ressources #

Je vous conseille vivement la lecture du guide suivant qui est très bien illustré pour comprendre le fonctionnement de dwm : Dave's Visual Guide to dwm

https://ratfactor.com/dwm

Et en bon humain, arpinux a beaucoup écrit sur dwm : Documentation de dwm en français par arpinux

https://arpinux.org/public/doc_arp_pdf/wms-dwm.pdf