/*
 * https ; gemini ;
 * tout ; log ; twtxt ;
 * à propos (@) ; ;
 */

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.

dwm
dmenu

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

Ainsi que quelques aperçus :

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

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 appelera 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 "à"):

[IMG]

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

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 :

ddesktop
lsdesktop

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 :

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 cherchez le besoin :

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... Par exemple, ça donne :

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

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

Cela ressemble à :

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.

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 :)

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

Et en bon humain, arpinux a beaucoup écrit sur dwm :

Documentation de dwm en français par arpinux
Exemples de configuration de dwm par arpinux