Как стать автором
Обновить

YAD

Это будет наглая реклама. Даже самореклама. Но тем не менее, в отличие от практически всех остальных реклам, я надеюсь, она будет таки полезна окружающим. Или хотя бы части из них.

Речь пойдет о шэле и иксах. Или как скрестить ежа с ужом и получить два метра колючей проволоки.

Немного предыстории. Я тулкитофоб. Не люблю qt. Потому что c++, который я тоже не люблю. Motif и соответственно все tk были идеальны. Пока не заснули в конце 90-х. Xaw — вещь, конечно, хорошая, но тоже убогая еще больше чем motif. Потому и пришлось остановиться на gtk, о чем пока и не жалею.

Теперь к делу. Для начала приведу любимую цитату из TAOUP Реймонда. Можно считать, что это эпиграф:

«В одной строке кода shell-сценария больше духа UNIX, чем в десяти тысячах строк на языке С!»

Есть в составе GNOME такая хорошая программа, как zenity. Позволяет создавать диалоговые окошки на манер dialog. Все хорошо, да только не развивается нифига. Пришлось форкать, т.к. в багтраке у них тишина, патчи чересчур сложные, да и вообще. Форкнул. Вроде получилось симпатично.

code.google.com/p/yad

Несколько примеров, чтобы понять отличия.

Пример нумер раз, редактор списка автоматом запускаемых программ, как это советует freedesktop:

#! /bin/bash

config_dir=${XDG_CONFIG_HOME:-$HOME/.config}
results=$(mktemp --tmpdir autostart.XXXXXXXXXX)

for f in $config_dir/autostart/*.desktop; do
    grep -m 1 -e '^[[:blank:]]*Exec' $f | cut -d = -f 2
    grep -m 1 -e '^[[:blank:]]*Name' $f | cut -d = -f 2
    grep -m 1 -e '^[[:blank:]]*Comment' $f | cut -d = -f 2
done | yad --width=500 --height=300 --title="Autostart editor" --image="gtk-execute" \
           --text="Add/remove autostart items" --list --editable --print-all \
           --multiple --column="Command" --column="Name" --column="Description" > $results

if [[ $? -eq 0 ]]; then
    rm -f $config_dir/autostart/*.desktop
    i=0
    cat $results | while read line; do
        eval $(echo $line | awk -F'|' '{printf "export NAME=\"%s\" COMMENT=\"%s\" COMMAND=\"%s\"", $2, $3, $1}')
        cat > $config_dir/autostart/$i$NAME.desktop << EOF
[Desktop Entry]
Encoding=UTF-8
Name=$NAME
Comment=$COMMENT
Exec=$COMMAND
StartupNotify=true
Terminal=false
EOF
        $((i++))
    done
    unset NAME COMMENT COMMAND
fi

rm -f $results
exit 0


Пример два, состоящий из двух частей. Автомонтирование флешек баз hal-ов, divicekit-ов и прочей ерунды.

Первое, создаем правила для udev:

KERNEL!="sd[a-z]*", GOTO="auto_mount_end"
ACTION=="add", PROGRAM!="/sbin/blkid %N", GOTO="auto_mount_end"

# Set environment
ACTION=="add", IMPORT{program}="/sbin/blkid -o udev -p -s TYPE -s LABEL %N"

# Global mount options
ACTION=="add", ENV{mount_options}="noatime,nodiratime,users,umask=0"

# Filesystem specific options
ACTION=="add", ENV{ID_FS_TYPE}=="vfat", ENV{mount_options}="%E{mount_options},showexec"
ACTION=="add", ENV{ID_FS_TYPE}=="ntfs", ENV{mount_options}="%E{mount_options},utf8"

# Get mount point
# use basename to correctly handle labels such as ../mnt/foo
ACTION=="add", ENV{ID_FS_LABEL}=="?*", PROGRAM="/usr/bin/basename '%E{ID_FS_LABEL}'", ENV{dir_name}="%c"
ACTION=="add", ENV{dir_name}!="?*", ENV{dir_name}="usbhd-%k"

# Main action
ACTION=="add", ENV{dir_name}=="?*", RUN+="/bin/mkdir -p '/mnt/usb/%E{dir_name}'", RUN+="/bin/mount -o %E{mount_options} /dev/%k '/mnt/usb/%E{dir_name}'"
ACTION=="remove", ENV{dir_name}=="?*", RUN+="/bin/umount -l '/mnt/usb/%E{dir_name}'", RUN+="/bin/rmdir '/mnt/usb/%E{dir_name}'"

LABEL="auto_mount_end"


И второе — следим за ними:

#! /bin/sh

BASEDIR=/mnt/usb
PIPE=$(mktemp -u --tmpdir ${0##*/}.XXXXXXXX)

function on_exit () {
    echo "quit" >&3
    rm -f $PIPE
}

function on_unmount () {
    gsu umount $1
    ret=$?
    if [[ $ret -eq 0 ]]; then
        notify-send -u normal -i drive-removable-media -t 900 \
            "${1##*/}" "${1##*/} unmounted successfully"
    else
        notify-send -u critical -i drive-removable-media -t 1200 \
            "${1##*/}" "Unmount ${1##*/} failed (error code $ret)!!!"
    fi
}

function update_state () {
    MENU=
    for d in $(find $BASEDIR -mindepth 1 -maxdepth 1 -type d); do
        MENU="${d##*/}!sh -c 'on_unmount $d'|$MENU" 
    done
    if [[ -z $MENU ]]; then
        echo "visible:false" >&3
    else
        echo "visible:true" >&3
        echo "menu:$MENU" >&3
    fi
}

mkfifo $PIPE
exec 3<> $PIPE

export -f on_unmount
trap on_exit SIGTERM SIGINT

yad --notification --listen \
    --image=drive-removable-media --text="Removable media" \
    --command="xdg-open $BASEDIR" <&3 &

update_state

inotifywait -m -e create -e delete $BASEDIR 2> /dev/null | while read LINE; do
    case $(echo $LINE | awk '{print $2}') in
        "CREATE,ISDIR") update_state ;;
        "DELETE,ISDIR") update_state ;;
    esac
done


Комментариев не даю к коду сознательно, так как считаю, что те, кому это может быть полезно, способны разобраться в коде сами.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.