#!/usr/bin/perl ############################################################################## # generates a file.menu format for Enlightenment out of menu hierarchies # # Copyright (C) 2003-2005 Kim Woelders # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies of the Software, its documentation and marketing & publicity # materials, and acknowledgment shall be given in the documentation, materials # and software packages that this Software was used. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ############################################################################## # Likely prefixes $Prefixes = "/usr/local:/usr:/opt:/opt/kde:$ENV{'KDEDIR'}"; $Prefixes = RemoveDuplcates($Prefixes); # Where to look for GNOME2/KDE2,3 stuff $AppDirs = MkDirList($Prefixes, "/share/applications:/share/applications/kde"); $IconDirs = MkDirList($Prefixes, "/share/pixmaps"); $IconDirsKDE = MkDirList($Prefixes, "/share/icons"); $Themes = "default.kde:hicolor:locolor"; # Where to look for GNOME1 apps $OldGnomeDirs = MkDirList($Prefixes, "/share/gnome/apps"); # Where to look for KDE1/2 apps $OldKdeDirs = MkDirList($Prefixes, "/share/applnk"); # Pick up env vars $EdirUser = "$ENV{'ECONFDIR'}"; $EdirRoot = "$ENV{'EROOT'}"; $EdirBin = "$ENV{'EBIN'}"; # Localization bits. There may be better ways to do this. $Lang = "$ENV{'LANG'}"; $loc1 = $loc2 = $loc3 = $Lang; $loc2 =~ s/[\.\@].*//; $loc3 =~ s/_.*//; $loc1 = "" if ($loc1 eq $loc2); $EdirUser = "$ENV{'HOME'}/.e16" unless $EdirUser; $EdirRoot = "/usr/share/enlightenment" unless $EdirRoot; $EdirBin = "/usr/bin" unless $EdirBin; $EdirIcons = "$EdirUser/icons"; $EdirMenus = "$EdirUser/menus"; $dbg = "$ENV{'E_MENUGEN_DBG'}"; # Put EBIN first in path $ENV{'PATH'} = "$EdirBin:$ENV{'PATH'}"; # Programs $DoConvert = `which convert`; $DoIconv = `which iconv`; @CatsRemove = ( "Qt", "QT", "GNOME", "KDE", "UtilityApplication", "Applications", "Application", "X-Red-Hat-Base-Only", "X-Red-Hat-BaseApplication", "X-Red-Hat-Base", "X-Red-Hat-ServerConfig", "X-Red-Hat-Extra", "X-KDE-information", "X-KDE-settings-accessibility", "X-KDE-settings-components", "X-KDE-settings-desktop", "X-KDE-settings-looknfeel", "X-KDE-settings-network", "X-KDE-settings-peripherals", "X-KDE-settings-power", "X-KDE-settings-security", "X-KDE-settings-sound", "X-KDE-settings-system", "X-KDE-settings-webbrowsing" ); @MainMenu = ( "t:User Menus", "m:User Application list:menus/user_apps.menu", "m:GNOME:menus/menus_GNOME/index.menu", "m:KDE:menus/menus_KDE/index.menu", "m:Other:menus/menus_Other/index.menu", "m:Enlightenment Epplets:menus/epplets.menu", "c:Restart Enlightenment:exit restart", "c:Log Out:exit logout" ); @UserAppsMenu = ( "t:User Application List", "x:Eterm:Eterm", "x:XTerm:xterm", "x:RXVT:rxvt", "x:Mozilla:mozilla", "x:Firefox:firefox", "x:Galeon:galeon", "x:Opera:opera", "x:Electric Eyes:ee", "x:Gmplayer:gmplayer", "x:Xine:xine", "x:The GIMP:gimp", "x:XV:xv", "x:GQView:gqview", "x:Gaim:gaim", "x:Grip:grip", "x:Xchat:xchat", "x:Xchat2:xchat2", "x:Xchat2:xchat-2", "x:XMag:xmag", "x:XMMS:xmms" ); # Remove duplicates and nulls in ':' separated dir list sub RemoveDuplcates { local $dl = shift; local @r; local %h; foreach $p (split(':', $dl)) { next unless $p; next if $h{$p}; $h{$p} = $p; push @r, $p; } return join(':', @r); } # Make : separated directory list, check that they exist sub MkDirList { local $dl = shift; local $sf = shift; local $d; local @r; foreach $p (split(':', $dl)) { foreach $q (split(':', $sf)) { $d = "$p$q"; push(@r, "$d") if -d "$d"; } } return join(':', @r); } # Make dir if non-existing sub MkDir { local $d = shift; mkdir("$d") unless (-d "$d"); } # Make simple menus sub MakeMenu { local $f = shift; local $m = shift; $f = "$EdirMenus/$f"; return if (-f "$f"); open(FD, ">$f"); foreach $e (@$m) { ($t, $n, $p) = split(':', $e); if ($t eq "t") { print FD "\"$n\"\n"; } elsif ($t eq "m") { print FD "\"$n\" NULL menu \"$p\"\n"; } elsif ($t eq "x") { print FD "\"$n\" NULL exec \"$p\"\n"; } elsif ($t eq "c") { print FD "\"$n\" NULL \"$p\"\n"; } } close(FD); } # Process a .desktop file sub ProcessFile { local $f = shift; local $Name, $Exec, $Icon, $Cats, $Type, $File; local $c; if (! -f "$f") { print "Not found: $f\n" if $dbg ge 1; return; } # Global ref no $N++; $Name = $Exec = $Icon = ""; $Nam1 = $Nam2 = $Nam3 = ""; $Cats = shift; $Type = shift; open(FI,$f) or return; while () { if (/^Name=(.*)$/) { $Name = $1; } elsif ($loc1 && /^Name\[$loc1\]=(.*)$/) { $Nam1 = $1; } elsif ($loc2 && /^Name\[$loc2\]=(.*)$/) { $Nam2 = $1; } elsif ($loc3 && /^Name\[$loc3\]=(.*)$/) { $Nam3 = $1; } elsif (/^Exec=(.*)$/) { $Exec = $1; } elsif (/^Icon=(.*)$/) { $Icon = $1; } elsif (/^OnlyShowIn=(.*);$/) { $Type = $1; } elsif (/^Categories=(.*)$/) { next if "$Cats"; # Given $Cats = $1; foreach $c (@CatsRemove) { $Cats =~ s/(^|;)$c;*/\1/g; } } elsif (/^Type=(.*)$/) { if ($1 ne "Application") { $Name = ""; last; } } if ($Nam1 || $Nam2 || $Nam3) { if ($Nam1) { $Name = $Nam1; } elsif ($Nam2) { $Name = $Nam2; } else { $Name = $Nam3; } $Name = `echo "$Name" | iconv -f UTF-8` if $DoIconv; chomp($Name); } } close FI; $Cats =~ s/ +$//; if (!$Name || !$Exec || !$Cats) { printf("Skipped: %-24s %-24s %-20s %-20s %s\n", $f, $Name, $Exec, $Icon, $Cats) if $dbg ge 1; return; } # Basename $File = $f; $File =~ s/^.*\///; printf("%-24s: %-24s %-20s %-20s %s\n", $File, $Name, $Exec, $Icon, $Cats) if $dbg ge 3; if (!$Type) { if ($File =~ /^gnome/) { $Type = "GNOME"; } elsif ($File =~ /^kde/) { $Type = "KDE"; } else { $Type = "Other"; } } $Namx = "$Name-$N"; # Make key unique $Namx =~ tr/A-Z/a-z/; # To lower case (for sorting) $File{$Namx} = $File; $Name{$Namx} = $Name; $Exec{$Namx} = $Exec; $Icon{$Namx} = $Icon; $Cats{$Namx} = $Cats; $Type{$Namx} = $Type; } # Process all .desktop files in a directory sub ProcessDir { local $d = shift; local $dx = shift; local $t = shift; local @l; local $f; @l = grep /\.desktop$/, ReadDir($d); foreach $f (@l) { $f = "$d/$f"; print "- File $f\n" if $dbg ge 2; ProcessFile("$f", "$dx", "$t"); } } # Process old style GNOME/KDE directories sub ProcessOldStyle { local $t = shift; local $dl = shift; local $d, $d2; local @d2l; foreach $d (split(':', $dl)) { print "Processing directory: $d\n" if $dbg ge 1; if (! -d "$d") { print "- Not found\n" if $dbg ge 1; next; } @d2l = grep !/^\./, ReadDir($d); foreach $d2 (@d2l) { print " Subdir: $d/$d2\n" if $dbg ge 1; next unless -d "$d/$d2"; ProcessDir("$d/$d2", "$d2", "$t"); } } } # Create scaled 18x18 pixel icon sub ScaleIcon { local $f = shift; local $g = $f; return $f unless $DoConvert; $g =~ s/^.*\///; $g =~ s/\..*$//; $g = "$EdirIcons/$g.png"; system("convert -geometry 18x18 $f $g"); return $g; } # Find that $#@! thing sub FindIcon { local $f = shift; return $f if (! $f); if (-f $f) { $i = ScaleIcon($f); return $i; } foreach $d (split(':', $IconDirs)) { $i = "$d/$f"; next unless -f $i; $i = ScaleIcon($i); return $i; } foreach $d (split(':', $IconDirsKDE)) { foreach $t (split(':', $Themes)) { foreach $u (split(':', "apps:filesystems:actions")) { $i = "$d/$t/16x16/$u/$f"; $i = "$i.png" unless ($f =~ /\.png$/); print "Testing $i\n" if $dbg >= 2; return $i if -f $i; } } } return $f; } # Make the Epplets menu sub MakeEppsMenu { local $f = shift; local $d; local %done; open(FD, ">$EdirMenus/$f"); print FD "\"Enlightenment Epplets\"\n"; foreach $d (split(':', $ENV{'PATH'})) { next unless -d $d; next if ($done{$d}); $done{$d} = 1; print "Looking for epplets in $d\n" if $dbg ge 1; @el = grep /\.epplet$/, ReadDir($d); foreach $e (@el) { $e =~ s/\.epplet$//; $i = "$EdirRoot/epplet_icons/$e.icon"; $i = ScaleIcon("$i") if -f "$i"; print FD "\"$e\" \"$i\" exec \"$d/$e.epplet\"\n"; } } close(FD); } # Make the menu for a given app type sub MakeAppsMenu { local $type = shift; local %menus; local $c, $k, $dir; $dir = "$EdirMenus/menus_$type"; print "Generating Menu: $type in $dir\n" if $dbg ge 1; MkDir($dir); # Sort the apps into categories foreach $k (sort(keys(%Name))) { next if ($Type{$k} ne $type); $c = $Cats{$k}; $c =~ s/;.*$//; # $menus{$c} = $k; push(@{$menus{$c}}, $k); } # Make top- and sub-menus open(FTopM, ">$dir/index.menu") or die "*** Couldn't create $dir/index.menu\n"; print FTopM "\"$type Menu\"\n"; foreach $m (sort(keys(%menus))) { open(FSubM, ">$dir/$m.menu") or die "*** Couldn't create $dir/$m.menu\n"; print "- Submenu: $m\n" if $dbg ge 2; print FTopM "\"$m\" \"\" menu \"$dir/$m.menu\"\n"; print FSubM "\"$m\"\n"; foreach $k (sort(@{$menus{$m}})) { print " - Item: $k\n" if $dbg ge 2; $icon = FindIcon($Icon{$k}); @exec = split(' ', $Exec{$k}); $exec = @exec[0]; printf FSubM "\"%s\" \"%s\" exec \"%s\"\n", $Name{$k}, $icon, $exec; } close(FSubM); } close(FTopM); } # Return list of files in dir sub ReadDir { local $dir = shift; local @dirs; opendir DH, $dir or die "*** Not a directory: $dir\n"; @dirs = readdir DH; closedir DH; return @dirs; } # Close all windows named "Message" (we assume they are E dialogs) sub CloseMessageWindows { open(WL, "eesh -ewait wl |"); while () { if (/\s*(\w+) : Message\s/) { system("eesh -e \"wop $1 close\""); } } close(WL); } ############################################################################## # Here we go ############################################################################## $N = 0; CloseMessageWindows(); system("eesh -e \"dialog_ok Menus are being generated... Please Wait.\""); # Process old style GNOME directories ProcessOldStyle("GNOME", "$OldGnomeDirs"); # Process old style KDE directories ProcessOldStyle("KDE", "$OldKdeDirs"); # Process new style (GNOME2, KDE2/3) directories foreach $d (split(':', $AppDirs)) { print "Processing directory: $d\n" if $dbg ge 1; if (! -d $d) { print "- Not found\n" if $dbg ge 1; next; } ProcessDir($d); } # Make menu dir and scaled icon dir MkDir("$EdirMenus"); MkDir("$EdirIcons"); # Make the menus MakeMenu("file.menu", \@MainMenu); MakeMenu("user_apps.menu", \@UserAppsMenu); MakeEppsMenu("epplets.menu"); MakeAppsMenu("GNOME"); MakeAppsMenu("KDE"); MakeAppsMenu("Other"); CloseMessageWindows(); system("eesh -e 'menus reload'"); system("eesh -e 'dialog_ok Menu generation complete.'");