You are not logged in.

#1 2011-06-20 17:10:49

I'mGeorge
Member
Registered: 2011-03-23
Posts: 150

creating an auto-generating menu for fluxbox

Fluxbox is one of the best wms for linux. If there's something that could replace any desktop, with low resources consumption, still being accessible and handy, than that's Fluxbox. The thing is when you install Fluxbox for the first time you feel something is lacking. That thing is the possibility of an auto-generating menu. Of course there's

fluxbox-generate_menu

and other likewise possibilities  but they kinda fail in doing what they should.   I'm a bit new to programming and even fresher when it comes to scripting in linux but I've though of a script that could do just that as it follows:

#!/bin/bash

while true
do
men="ArchSoft"
ver=$(grep "$men" ~/.fluxbox/menu | sed 's/.*(//; s/).*//' | tail -1)
if [ $men == $ver ]
then
data="$(date +%Y-%m-%d\ %k:%M)" 
data2="$(grep "$data" /var/log/pacman.log | grep installed | sed "s/\[//g; s/\].*//g" | tail -1)"
 if [ "$data" == "$data2" ]
 then
nr="$(grep "$data" /var/log/pacman.log | grep installed | wc -l)"
int=$(seq 1 $nr)
for i in $int
do
ch=$(grep "$data" /var/log/pacman.log | grep installed | sed 's/.*installed//g; s/(.*//g; s/ //g' | head -$i | tail -1)
chr=$(grep "$ch" ~/.fluxbox/menu | sed 's/.*(//; s/).*//' | tail -1)
chb=$(ls /usr/bin | grep "$ch" | sed "s/.*$ch.*/$ch/" | tail -1)
la=$(ls /usr/share/icons/hicolor/48x48/apps | grep $ch | sed "s/.*$ch.*/$ch/"| tail -1)
lb=$(ls /usr/share/pixmaps | grep $ch | sed "s/.*$ch.*/$ch/" | tail -1)
   if [ $ch == $chb ]
   then
       if [ $ch == $chr ]
       then
       echo "there's already a menu entry"
       else
           if [ $ch == $la ]
           then
           sed -i "/^\[submenu\] ($men)$/a[exec]   ($ch) {$ch} </usr/share/icons/hicolor/48x48/apps/$ch.png>" ~/.fluxbox/menu
           sleep 1
           fluxbox restart
           elif [ $ch == $lb ]
           then
           sed -i "/^\[submenu\] ($men)$/a[exec]   ($ch) {$ch} </usr/share/pixmaps/$ch.png>" ~/.fluxbox/menu
           sleep 1
           fluxbox restart
           fi
       fi
   fi
done
 fi
rdata="$(grep "$data" /var/log/pacman.log | grep removed | sed "s/\[//g; s/\].*//g" | tail -1)"
          if [ "$data" == "$rdata" ]
              then
              nrem="$(grep "$data" /var/log/pacman.log | grep removed | wc -l)"
              inrem=$(seq 1 $nrem)
              for i in $inrem
              do
              rem=$(grep "$data" /var/log/pacman.log | grep removed | sed 's/.*removed//g; s/(.*//g; s/ //g' | head -$i | tail -1)
              remr=$(grep "$rem" ~/.fluxbox/menu | sed 's/.*(//; s/).*//' | tail -1)
                 if [ $rem == $remr ]
                 then
                 sed -i "/$rem/d" ~/.fluxbox/menu
                 sleep 1
                 fluxbox restart
                 else
                 echo "no menu entry to remove"
                 fi
              done
              fi
else
sed -i "/^\[begin\] (Fluxbox)$/a[submenu] ($men)\n[end]" ~/.fluxbox/menu
fi
clear
sleep 7
done

   

Explanation:

I've used

whilde true
do
......
sleep 7
done

to create an endless loop where "sleep" was used so it could take a break, therefore reducing hardware consumption

men="ArchSoft"
ver=$(grep "$men" ~/.fluxbox/menu | sed 's/.*(//; s/).*//' | tail -1)
if [ $men == $ver ]
then
....
else
sed -i "/^\[begin\] (Fluxbox)$/a[submenu] ($men)\n[end]" ~/.fluxbox/menu
fi

This checks if the submenu where everything should automatically be added as entries  are already there, if not it creates them under the beginning of fluxbox menu script with the name ArchSoft. 

data="$(date +%Y-%m-%d\ %k:%M)" 
data2="$(grep "$data" /var/log/pacman.log | grep installed | sed "s/\[//g; s/\].*//g" | tail -1)"
 if [ "$data" == "$data2" ]
 then
....
fi

this compares the actual data from the system clock with the data of the installed apps shown in pacman .log and if it finds a similar data of the installed apps it procedes to further steps

nr="$(grep "$data" /var/log/pacman.log | grep installed | wc -l)"
int=$(seq 1 $nr)
for i in $int
do
ch=$(grep "$data" /var/log/pacman.log | grep installed | sed 's/.*installed//g; s/(.*//g; s/ //g' | head -$i | tail -1)
chr=$(grep "$ch" ~/.fluxbox/menu | sed 's/.*(//; s/).*//' | tail -1)
chb=$(ls /usr/bin | grep "$ch" | sed "s/.*$ch.*/$ch/" | tail -1)
la=$(ls /usr/share/icons/hicolor/48x48/apps | grep $ch | sed "s/.*$ch.*/$ch/"| tail -1)
lb=$(ls /usr/share/pixmaps | grep $ch | sed "s/.*$ch.*/$ch/" | tail -1)
   if [ $ch == $chb ]
   then
       if [ $ch == $chr ]
       then
       echo "there's already a menu entry"
       else
           if [ $ch == $la ]
           then
           sed -i "/^\[submenu\] ($men)$/a[exec]   ($ch) {$ch} </usr/share/icons/hicolor/48x48/apps/$ch.png>" ~/.fluxbox/menu
           sleep 1
           fluxbox restart
           elif [ $ch == $lb ]
           then
           sed -i "/^\[submenu\] ($men)$/a[exec]   ($ch) {$ch} </usr/share/pixmaps/$ch.png>" ~/.fluxbox/menu
           sleep 1
           fluxbox restart
           fi
       fi
   fi
done

Here  because in pacman.log, the data of installed apps is shown in this manner YY-MM-DD hh:mm I had to consider using "for do", because in a minute a lot of applications can be installed using only a single "$pacman -S apps" command. Therefore I had to add somehow every app installed in a minute, separately to ~/fluxbox/menu. If the data of the installed apps in pacaman.log was show in this manner YY-MM-DD hh:mm:ss, therefore including seconds things would had been a lot more easier and precise, but I had to find a solution to that matter, and that solution was using "for do" .
Also here it checks if the installed program shows as an executable in /usr/bin and if it has an icon in  /usr/share/icons/hicolor/48x48/apps/ or in /usr/share/pixmaps/, and only than it procedes in adding an entry to fluxbox menu for that app. This was necessary because not all programs installed, that have executables in /usr/bin are meant to be displayed as a fluxbox menu entry. Checking for an icon being a filter and at the same time something kinda useful for the overall aspect of the menu.

rdata="$(grep "$data" /var/log/pacman.log | grep removed | sed "s/\[//g; s/\].*//g" | tail -1)"
          if [ "$data" == "$rdata" ]
              then
              nrem="$(grep "$data" /var/log/pacman.log | grep removed | wc -l)"
              inrem=$(seq 1 $nrem)
              for i in $inrem
              do
              rem=$(grep "$data" /var/log/pacman.log | grep removed | sed 's/.*removed//g; s/(.*//g; s/ //g' | head -$i | tail -1)
              remr=$(grep "$rem" ~/.fluxbox/menu | sed 's/.*(//; s/).*//' | tail -1)
                 if [ $rem == $remr ]
                 then
                 sed -i "/$rem/d" ~/.fluxbox/menu
                 sleep 1
                 fluxbox restart
                 else
                 echo "no menu entry to remove"
                 fi
              done
              fi

This part of the script removes the data from the menu entry pretty much in the same manner it was added, so I won't give further explanations.

The Trouble:
Most applications are added and removed just fine in the fluxbox menu entry, but some like chromium are added more than once and after pacman -R app they aren't removed. The script has still a lot of flaws, most of them because I'm new to scripting, but if someone can improve it or give suggestions it would be highly appreciated. Also if anybody that finds the script worthy enough, wants to develop it as his own I have nothing against it, just tell what changes and improvements you have brought as I wanna learn too.

Also my goal is to make a daemon out of it, any suggestions in this direction would be highly appreciated.

Thanks for your time and understanding, mostly thanks to those that helped me a bit in understanding the syntax, like  @Karol & @falconindy. You rule, 'cause  you make linux  seam like one big happy family big_smile

George

Last edited by I'mGeorge (2011-06-20 19:43:08)


I've first installed Arch in March

Offline

#2 2011-06-29 00:21:25

xelados
Member
Registered: 2007-06-02
Posts: 314
Website

Re: creating an auto-generating menu for fluxbox

This is an awesome idea. I've wanted to do something like this for a little while, though not in bash...

Since I'm not great in bash, I may make one in C (for learning) or Python (ditto) and comment on your implementation.

If I understand right, you're building a menu first, then deleting parts of it as you go. Would it not be smarter to create a function for adding entries and call it only after you've decided whether an app belongs in the menu? Something like this:

function add_to_menu() {
# echo whatever to the config file
}

if (app is on system && has an icon somewhere in /usr/share or /opt) {
add_to_menu(foo)
}

Personally, I would approach this by using a definition or grouping list (so you can make submenus) and organize your apps that way. I'd probably use an sqlite db or an ini file or some other way to store the heirarchy, then generate the menu. It looks like you've already put a lot of effort into this, though, so I wish you luck on it!

Offline

Board footer

Powered by FluxBB