Fvwm - dynamická menu

Úvod

Na potřebu vytvářet menu dynamicky jsem narazil chvíli poté, co se mi na disku shromáždilo o něco málo více než dvě fotky, a já hledal efektivní způsob, jak střídat na pozadí pracovní plochy depresivní obrázek propíchané holky s depresivním obrázkem podzimního Radhoště v mlze. Fvwm je naštěstí inteligentní okenní manažer a pamatuje i na mou potřebu vytvářet menu dynamicky například podle obsahu nějakého adresáře.

Podobný nápad měli i tvůrci fvwm, protože přímo součástí distribučního balíčku je i v perlu napsaný program fvwm-menu-directory, který je právě na procházení adresářových struktur pomocí menu fvwm určený. Při studiu dynamických menu mi program fvwm-menu-directory významně pomohl.

Program fvwm-menu-directory není v distribuci fvwm jediný program pro tvorbu dynamických menu. Zajímavou inspirací může být například fvwm-menu-headlines - program dokáže z internetu stáhnout titulky článků z různých zpravodajských serverů a při zvolení nastartovat prohlížeč s obsahem příslušného článku - zřejmě tedy rss čtečka integrovaná přímo do okenního systému. Další program, fvwm-menu-desktop, vytváří menu z definic prostředí Gnome či KDE. Přiznám se, že netuším, jak tyto programy fungují - nikdy jsem je nezkoušel.

Příkazy pro tvorbu dynamických menu

Při tvorbě různých funkcí a menu si je třeba uvědomit, že narozdíl od jiných "programovacích jazyků" konfigurační jazyk fvwm umožňuje vytvářet jedno menu nebo funkci na několika místech. Příkaz AddToMenu můžeme použít na začátku konfiguračního souboru, pokračovat s tvorbou stejného menu uprostřed, ve zcela jiném kontextu, a celé menu dokončit na posledních řádcích konfiguračního souboru, případně v souboru uloženém někde úplně jinde. Takový přístup jistě není nejlepší konfigurační technikou, ale usnadňuje to dynamickou tvorbu konfigurace fvwm. Zkušenému programátorovi/konfigurátorovi by nemělo činit problémy udržet zmatek v konfiguračním souboru na zvládnutelné úrovni.

Při tvorbě dynamických menu je přijatelným postupem definovat úvodní část menu staticky v konfiguračním souboru:

AddToMenu MojeMenu
+ "Moje menu" Title
+ "" Nop
+ "Statická akce" Exec exec ...

a o kus dál (dynamicky) připojit k menu další položky:

AddToMenu MojeMenu "Položka v menu" Exec exec...

Read

Přečte část konfigurace z externího souboru. Pro nefalšovaná dynamická menu není příkaz Read úplně nejvhodnější vzhledem ke statické povaze normálního souboru. Příkaz read je obyčejnou obdobou například direktivy #include z jazyka C.

PipeRead

Přečte část konfigurace ze standardního výstupu nějakého programu. Program je spuštěn pomocí /bin/sh, takže jako externí program lze uvést i jednoduchý skript shellu:

AddToMenu HomeDirMenu
PipeRead 'for i in $HOME/*; \
    do echo "+ \"$i\" Exec xterm -e vi \"$i\""; done'

Příklad vytvoří menu se seznamem všech souborů v domácím adresáři uživatele a v případě zvolení některé položky nastartuje xterm s editorem vi.

MissingSubmenuFunction

Adresářová struktura bývá obecně ve stromovém tvaru, velmi složitá, a předem nelze říci, co na souborovém systému najdeme. Fvwm dovede dynamicky vytvářet nejen jednotlivé položky v menu, ale i celá menu. Příkazem MissingSubmenuFuction okennímu manažeru fvwm sdělujeme, která funkce mu pomůže při vytváření chybějících podmenu. Pro každé dynamické menu lze samozřejmě uvést jinou funkci.

Funkci je jako první parametr předané jméno vytvářeného menu. Parametr je přístupný, podobně jako v shellu, jako "$0".

AddToFunc FuncFvwmMenuDirectory
+ I PipeRead "fvwm-menu-directory -d '$0'"

AddToMenu Adresare "Adresáře" title
+ MissingSubmenuFunction FuncFvwmMenuDirectory
+ "Adresář [$HOME]" Popup "$[HOME]"
+ "Adresář /"       Popup "/"

V uvedeném příkladu je pro tvorbu chybějících menu použitý externí program fvwm-menu-directory. Menu jím generovaná předpokládají, že funkce pro tvorbu menu se jmenuje FuncFvwmMenuDirectory, ale není problém jméno funkce změnit parametrem --func-name "jméno funkce". Program fvwm-menu-directory je napsaný v perlu a je možné jej spustit přímo na povelové řádce a prohlédnout si jeho výstup:

DestroyMenu recreate "/"
AddToMenu "/"
+ DynamicPopDownAction DestroyMenu "/"
+ MissingSubmenuFunction FuncFvwmMenuDirectory
+ "/" Exec cd "/"; xterm -e /bin/bash
+ "" Nop
+ "bin" Popup "bin" item +100 c
....

DynamicPopdownAction a DynamicPopupAction

Příkazy umožňují spustit nějakou akci při zobrazení nebo skrytí menu. Protože tvoříme menu dynamicky a předpokládáme, že obsah menu se může pokaždé změnit, je dobré takové menu po použití zrušit, jinak by se nám v menu hromadily položky jako horníci v dolech:

AddToMenu MojeMenu DynamicPopDownAction  DestroyMenu MojeMenu

Pro vytváření menu se dá použít příkaz DynamicPopupAction:

AddToMenu Adresare
+ DynamicPopDownAction DestroyMenu Adresare
+ DynamicPopUpAction PipeRead \
  'for i in /tmp/*; do echo "AddToMenu Adresare \\"$i\\" Nop"; done'

Příklad nic užitečného nedělá, pouze vypisuje soubory v adresáři /tmp, ale lze na něm hezky demonstrovat použití příkazů DynamicPopDownAction a DynamicPopUpAction.

No a to je v zásadě vše, co nám stačí k tvorbě dynamických menu.

Užitečný fungující příklad

Ve svém domácím adresáři jsem si vyrobil adresář .podklad a do něj uložil všechny obrázky, které chci mít občas na ploše. Obrázky jsem si hezky roztřídil do podadresářů podle témat.

Někam do cesty (u mě je to adresář /usr/local/bin) jsem uložil jednoduchý skript:

#!/bin/sh

if [ "$1" = "--menu" ]; then
    DIR="$2"
    cd $DIR
    echo "DestroyMenu recreate \"$DIR\""
    echo "AddToMenu \"$DIR\""
    echo "+ DynamicPopDownAction DestroyMenu \"$DIR\""
    echo "+ MissingSubmenuFunction FuncPodkladDir"
    # První se zpracují adresáře
    find * -type d -maxdepth 0 -print | while read i
        do
        echo "+ \"$i\" Popup \"${DIR}${i}\""
        done
    # Pak se vyhledají a zpracují soubory s obrázky
    find *.jpg *.jpeg -type f -maxdepth 1 -print | while read i
        do
        # jména souborů očesat o příponu
        nn="`echo $i | sed 's/\.jpg$//; s/\.jpeg$//;'`"
        echo "+ \"$nn\" Exec podklad xloadimage -border black -center -onroot \"\\\"${DIR}/${i}\\\"\""
        done
    exit
    fi

# Skript je volaný s parametry, které říkají, jak zobrazit obrázek na
# ploše obrazovky
if [ $# -gt 0 ]; then
    echo "$@" > $HOME/.podklad/podklad.cfg
    fi

# Skript je volaný bez parametrů, z minula ale máme uložený příkaz
# pro zobrazení obrázku v souboru podklad.cfg
if [ -r "$HOME/.podklad/podklad.cfg" ]; then
    . $HOME/.podklad/podklad.cfg
    fi

Do konfiguračního souboru fvwm jsem doplnil řádky:

AddToFunc FuncPodkladDir
+ I PipeRead "podklad --menu '$0'"

AddToMenu Podklad
+ MissingSubmenuFunction FuncPodkladDir
+ "Podklad obrazovky" title
+ "Čistý černý podklad" Exec podklad xsetroot -solid Black
+ "Čistý modrý podklad" Exec podklad xsetroot -solid MidnigtBlue
+ "" Nop
+ "Obrázky" Popup $[HOME]/.podklad/

Skript se volá třemi různými způsoby. Z fvwm je třeba zavolat skript s parametry --menu jmeno_adresare - pak se vygeneruje seznam obrázků (pro jednoduchost soubory s příponou jpg a jpeg) v podobě dynamického menu. Při zvolení některé položky se zavolá skript podruhé a jako parametr se mu předá celý postup, kterým se má nastavit na pracovní plochu požadovaný obrázek (volání xloadimage). Potřetí se skript volá bez parametrů při startu fvwm - v tom případě si skript sáhne na disk do souboru .podklad/podklad.cfg, kde má od minula uložené, jak má nastavit pozadí pracovní plochy.

Závěr

První díl seriálu o fvwm jsem napsal téměř před rokem. Jsem rád, že jsem konečně našel sílu napsat vše, co jsem původně zamýšlel, a že jsem dokázal seriál dokončit.