blob: 14fdc5abdb8401e38328da1beaa7376c4cf2cfa4 (
plain) (
tree)
|
|
#!/usr/bin/perl
#
# Alternate fluxbox-generate_menu. Searches all the installed
# .desktop files to generate the menu.
#
use strict;
use warnings;
use File::Find;
use File::Which;
my $fluxbox_menu = "$ENV{HOME}/.fluxbox/menu";
my @desktop_dirs = ('/usr/share/applications', "$ENV{HOME}/.local/share/applications");
my @desktop_files = ();
my %desktop_entries;
for my $dir (@desktop_dirs) {
opendir (my $dh, $dir) or die "opendir($dir)";
my @files = grep { /\.desktop$/ && -f "$dir/$_" } readdir ($dh);
push @desktop_files, map { "$dir/$_" } @files;
closedir ($dh);
}
foreach my $file (@desktop_files) {
open (my $fh, "<$file") or die "open($file)";
my %entry = (file => $file);
my $header_found = 0;
foreach my $line (<$fh>) {
chomp $line;
next if $line =~ m/^\s*#/;
if ($line =~ m/\[Desktop Entry\]/) { $header_found = 1; next; }
next unless $header_found;
last if $line =~ m/^\[.+\]/;
my ($k, $v) = split (/=/, $line);
next unless $k && $v;
next if $k =~ m/\[[-\w@]+\]$/; # Skip alt language entries;
next if $k eq 'OnlyShowIn' && $v !~ m/fluxbox/i;
$entry{$k} = $v;
}
if ($entry{Name} &&
! (($entry{Hidden} && $entry{Hidden} eq 'true') ||
($entry{NoDisplay} && $entry{NoDisplay} eq 'true'))) {
$desktop_entries{$entry{Name}} = \%entry;
}
}
# See https://specifications.freedesktop.org/menu-spec/latest/apa.html
# Sorted in descending order of menu preference
my @menus = qw/TerminalEmulator
Network
AudioVideo
Graphics
Science
Development
Game
Utility
Office
System
Other/;
my %menus;
name: foreach my $name (sort keys %desktop_entries) {
my @categories = split (';', $desktop_entries{$name}->{Categories} // 'Other');
next if grep { /^(X-)?(XFCE|LXDE)(-Settings)?$/ } @categories;
next unless which split (' ', $desktop_entries{$name}->{Exec});
foreach my $menu (@menus) {
if (grep { /^$menu$/ } @categories) {
$menus{$menu}->{$name} = $desktop_entries{$name};
next name;
}
}
$menus{Other}->{$desktop_entries{$name}->{Name}} = $desktop_entries{$name};
}
rename $fluxbox_menu, "$fluxbox_menu.bak" or die "rename($fluxbox_menu,$fluxbox_menu.bak)";
open (my $fh, ">$fluxbox_menu") or die "open($fluxbox_menu)";
print $fh <<"HEADER";
# Generated by fluxbox-generate_menu
[begin] (Fluxbox)
[encoding] {UTF-8}
[exec] (Terminator) {terminator} </usr/share/icons/hicolor/48x48/apps/terminator.png>
[exec] (firefox) {firefox} </usr/share/icons/nuoveXT2/32x32/apps/firefox.png>
[exec] (thunderbird) {thunderbird} </usr/share/icons/hicolor/256x256/apps/thunderbird-icon.png>
[exec] (Run) {fbrun}
[exec] (Suspend to RAM) {gotosleep ram}
[exec] (Suspend to Disk) {gotosleep disk}
HEADER
foreach my $menu (@menus) {
next unless exists $menus{$menu};
my %rename = (TerminalEmulator => 'Terminals',
AudioVideo => 'Media',
Game => 'Games');
my $menuname = $rename{$menu} // $menu;
print $fh "[submenu] ($menuname)\n";
foreach my $name (sort keys %{$menus{$menu}}) {
my $icontext = '';
my $foundicon;
my $icon = $desktop_entries{$name}->{Icon};
if ($icon) {
if (-f $icon) {
$icontext = " <$icon>";
} else {
# Play a game of find the icon
find (sub {
if ($_ =~ m/$icon/ && ! defined ($foundicon) && $_ =~ m/\.(png|jpg|jpeg|xpm)$/) {
$foundicon = $File::Find::name;
}
}, ("$ENV{HOME}/.local/share/icons",
qw(/usr/share/icons/hicolor
/usr/share/icons/
/usr/share/pixmaps)));
if (defined ($foundicon)) {
$icontext = " <$foundicon>";
}
}
}
my $exec = $desktop_entries{$name}->{Exec};
# Remove file/url arguments (they make no sense here) and deprecated entries
$exec =~ s/%[fFuUdDnNvm]//g;
# Replace %i (icon), %c (name), and %k (desktop file)
$exec =~ s/%i/--icon $foundicon/g if $foundicon;
$exec =~ s/%c/$name/g;
$exec =~ s/%k/$desktop_entries{$name}->{file}/g;
print $fh " [exec] ($name) {$exec}$icontext\n";
}
print $fh "[end]\n";
}
print $fh <<"USER";
[submenu] (User Programs)
[exec] (VMware) {/usr/bin/vmware}
[exec] (KiCad) {/usr/bin/kicad}
[exec] (Eagle) {/opt/bin/eagle}
[exec] (GThumb) {/usr/bin/gthumb}
[exec] (QBitTorrent) {/usr/bin/qbittorrent}
[exec] (HandBrake) {/usr/bin/ghb}
[end]
USER
print $fh <<"FOOTER";
[submenu] (Fluxbox menu)
[config] (Configure)
[submenu] (Styles)
[include] (/usr/share/fluxbox/menu.d/styles/)
[end]
[workspaces] (Workspace List)
[submenu] (Tools)
[exec] (Window name) {xprop WM_CLASS|cut -d \" -f 2|gxmessage -file - -center}
[exec] (Run) {fbrun}
[exec] (Regen Menu) {fluxbox-generate_menu -ds -is}
[end]
[submenu] (Window Managers)
[restart] (openbox) {openbox} </usr/share/pixmaps/openbox.png>
[end]
[commanddialog] (Fluxbox Command)
[reconfig] (Reload config)
[restart] (Restart)
[exec] (About) {(fluxbox -v; fluxbox -info | sed 1d) | gxmessage -file - -center}
[separator]
[exit] (Exit)
[end]
[endencoding]
[end]
FOOTER
close ($fh);
|