#!/usr/bin/perl # # Copyright 2006, 2007 by Manuel Carrasco # # This file is part of the LookXP project, and may only be used, modified, # and distributed under the terms of the LookXP project license, # LICENSE.TXT. By continuing to use, modify, or distribute this file you # indicate that you have read the license and understand and accept it # fully. # # http://lxp.sourceforge.net # # This program generate a icewm menu using: # xml files: /etc/xdg/menus # mnu files: /usr/share/desktop-directories # app files: /usr/share/applications/* and /usr/app-install/desktop # ico files: /usr/share/pixmaps and /usr/share/icons # if there aren't xml files this script has a hardcoded menu (from ubuntu) # # Usage lxp-menu-generator --help to view options availables # our $VERSION="0.2-1b"; use strict; ##################################################################### package ICE::DVars; use File::Find; use File::Basename; use Data::Dumper; our @DIRS_ICONS=('/usr/share/pixmaps', '/usr/share/icons', '/usr/share/app-install/icons'); our $DIR_MENU = "/etc/xdg/menus"; our $DIR_DIRS = "/usr/share/desktop-directories/"; our @DIRS_APPS = ('/usr/share/applications', '/usr/app-install/desktop'); our @DIRS_APPS_KDE = ('/opt/kde3/share/apps', '/usr/share/apps'. '/usr/share/applications/kde'); our $APP_FILE = "$DIR_MENU/applications.menu"; our $VALID_TAGS = "(CATEGORY)|(FILENAME)|(DIRECTORY)|(NAME)|(TYPE)|(MERGEFILE)"; our $DBG = 0; our $comments = 0; our $iconsize=32; our %filesdone; our %appsdone; our %appsgksu; our %iconfiles; our %execfiles; sub indent { my ($cont) = @_; my $ret = ''; for (my $i=0; $i<$cont; $i ++) { $ret .= " "; } return $ret; } ## find the correct command line for the application: # remove %x parameters # also remember if the application needs gksu sub getAppExec { my ($ap) = @_; return if (!$ap); return if ($ap->{NODISPLAY} && $ap->{NODISPLAY} =~ /true/i); my $exec = $ap->{EXEC}; $exec =~ s/^\s+//g; #return if ($exec !~ /kmplayer/); return if (!$exec || $exec eq ''); # %u , %f , %c caption, --icon %i, --miniicon %m $exec =~ s/\"(\%[Uufim])\"/$1/g; $exec =~ s/[\s]*\%[Uufim][\s]*/ /g; # my ($gksu, $cmd, $args); if ($exec =~ /^[^\s]+gksu\s+([^\s]+)(.*)$/) { $gksu=1; $cmd=$1; $args=$2; } elsif ($exec =~ /^([^\s]+)(.*)$/){ $gksu=0; $cmd=$1; $args=$2; } my $bexec = basename($cmd); return if ($bexec eq ''); $execfiles{$bexec}=$cmd if (!$execfiles{$bexec} && -x $cmd ); return if (!$execfiles{$bexec}); if ($gksu || $appsgksu{$bexec} ) { $exec = $execfiles{gksu} . " " . $execfiles{$bexec}; $appsgksu{$bexec} = 1; } else { $exec = $execfiles{$bexec}; } if ($args && $args ne '') { $args =~ s/\%c/$bexec/c; $exec .= " " . $args; } return ($exec, $bexec); } ## look for files that match $expr into all folders an subfolders of @dirs sub findFiles { my ($expr, @dirs) = @_; my @files; find ( sub { my $str = 'push @files, "$File::Find::dir/$_" if ('.$expr.');'; eval $str; }, @dirs ); return @files; } ## find all images and cache it in a hash table %iconfiles sub LoadIconFiles { if ($comments) { print STDERR "Looking for icons in: " . join(" ", @DIRS_ICONS) . "\n"; } find( sub { if (/.png$|.xpm$/) { my $f = $_; my $d = $File::Find::dir; my $n = basename($f, ".png", ".xpm"); # if the image is under a directory name 16x16, 32x32 etc. if ($d =~ /\/(\d\dx\d\d)\//) { $iconfiles{$n}{"dir$1"}=$d; $iconfiles{$n}{dir}=$d if (!defined $iconfiles{$n}{dir}); } else { $iconfiles{$n}{dir}=$d; } $iconfiles{$n}{name}=$f; } } , @DIRS_ICONS); } ## look for a image in the hash table %iconfiles sub findIcon { my ($name, $size) = @_; return if (!$name || $name eq ''); return ($name) if (-f $name); my $n = basename($name, ".png", ".xpm"); $size = "$iconsize" if (!$size); my $dir = "dir"; $dir = "dir${size}x${size}" if (defined $iconfiles{$n}{"dir${size}x${size}"}); my $file = $iconfiles{$n}{$dir} . "/" . $iconfiles{$n}{name}; return (!-d $file && -f $file) ? $file : "-"; } ## find all executable files in PATH directories and chache them sub LoadExecFiles { if ($comments) { print STDERR "Looking for binaries in: " . $ENV{PATH} . "\n"; } my @path_dirs = split(":", $ENV{PATH}); find ( sub { my $n = basename($_); my $f = "$File::Find::dir/$_"; $execfiles{$n}="$f" if (-x $f); }, split(":", $ENV{PATH}) ); } sub findExec { my ($n) = @_; return $execfiles{$n}; } ##################################################################### package ICE::DApp; sub new { bless { NAME => undef, CATEGORY => undef, DESCRIPTION => undef, }, shift; } ##################################################################### package ICE::DMenu; #use Data::Dumper; sub new { bless { NAME => undef, TYPE => undef, ELEMENTS => [], #PARENT => undef, #FILE => {} }, shift; } ## return a string representing the $apps menu sub renderMenu { my ($self, $apps, $cont, $showRoot, $uniq, $showicons, $hideSub, $maxitems) = @_; my $ret = ''; return($ret) if (!$apps); $ret .= ICE::DVars::indent($cont) ."# renderMenu -> CONT:$cont ROOT:$showRoot UNIQ:$uniq ICONS:$showicons HIDESUBM:$hideSub MAXITEMS:$maxitems\n" if ($comments); my $kids = 0; my @elements = @{$self->{ELEMENTS}}; $kids += $#elements + 1; my @apps = $apps->getElements($self, $cont+1); my @files = split(/ +/, $self->{FILENAME}); foreach my $file (@files) { my $ap = $apps->getElement($file); ### next if (!$ap || !$ap->{EXEC}); my ($exec, $bexec) = ICE::DVars::getAppExec($ap); next if (!$exec); push @apps, $ap; } $kids += $#apps + 1; return($ret) if ($kids < 1); my $dir = $self->{DIRECTORY}; return($ret) if (!$dir); my $file = "$DIR_DIRS/$dir"; $self->loadDesktopDir($file); my ($name, $comment, $icon, $type, $cats, $xmlfile, $filename) = ($self->{NAME}, $self->{COMMENT}, $self->{ICON}, $self->{TYPE}, $self->{CATEGORY}, $self->{XMLFILE}, $self->{FILENAME}); ## Submenus of this menu my ($mntContent, $mitems, $pitems) = ('', 0, 0); foreach my $submenu (sort { return lc $a->{NAME} cmp lc $b->{NAME}; } @elements) { next if ($submenu->{DIRECTORY} =~ /more/i || $submenu->{DIRECTORY} =~ /other/i || $submenu->{DIRECTORY} =~ /unknown/i ); my $txt = $submenu->renderMenu($apps, $cont+2, 1, $uniq, $showicons, $hideSub, $maxitems); if (length($txt)) { $mntContent .= $txt; $mitems ++; } } ## Applications of this menu my %menuappsdone; foreach my $ap (sort { lc $a->{NAME} cmp lc $b->{NAME} } @apps) { my ($name, $comment, $icon, $type, $cat, $afile) = ($ap->{NAME}, $ap->{COMMENT}, $ap->{ICON}, $ap->{TYPE}, $ap->{CATEGORIES}, $ap->{FILE}); my ($exec,$bexec) = ICE::DVars::getAppExec($ap); next if (!$exec); my $rep = ""; next if ($uniq && $appsdone{$exec}); $appsdone{$exec}=1; $rep = (defined $menuappsdone{$exec}) ? '### ' : ''; $icon = ICE::DVars::findIcon($icon); $icon = '-' if (!$showicons || !$icon || $icon eq ''); if ($comments) { $mntContent .= ICE::DVars::indent($cont+1) . "#### $afile\n"; $mntContent .= ICE::DVars::indent($cont+1) . "# $comment\n"; $mntContent .= ICE::DVars::indent($cont+1) . "# $cat\n"; } my $txt = ICE::DVars::indent($cont+1) . $rep . "prog \"$name\" \"$icon\" $exec\n"; $mntContent .= $txt; $pitems ++; $menuappsdone{$exec}=1; } ## This Menu and its items if ($showRoot && $mntContent ne '') { if ($comments) { $ret .= ICE::DVars::indent($cont) . "# NAME: $name\n"; $ret .= ICE::DVars::indent($cont) . "# COMMENT: $comment\n"; $ret .= ICE::DVars::indent($cont) . "# XML: $xmlfile\n"; $ret .= ICE::DVars::indent($cont) . "# FILE: $filename\n"; $ret .= ICE::DVars::indent($cont) . "# CATEG.: $cats\n"; $ret .= ICE::DVars::indent($cont) . "# CHILDREN: kids: $kids mitems: $mitems pitems: $pitems\n"; } $icon = ICE::DVars::findIcon($icon); $icon = '-' if (!$icon || $icon eq ''); if ( !$hideSub || ($mitems + $pitems) > 1) { if ( $pitems > $maxitems) { ## split this huge menu into small submenus my $div = int($pitems / $maxitems); $div ++ if ($pitems % $maxitems); $maxitems = int($pitems / $div); $maxitems ++ if ($pitems % $div); $ret .= ICE::DVars::indent($cont) . "menu \"$name\" \"$icon\" {\n"; $ret .= ICE::DVars::indent($cont) . "##### INI Splitted menu $name\n" if ($comments); my $acont=0; my $txt=''; my $let=''; foreach my $line (split(/\n/, $mntContent)) { if ($let eq '' && $line =~ /^\s*prog \"([A-z])(.)/) { $let = "(". uc ($1) . lc ($2) . "...)"; } $txt .= "$line\n"; $acont ++ if ($line !~ /^#/); if ( !($acont % $maxitems) ) { my $idx = int($acont / $maxitems); #prog "KHexEdit" $ret .= ICE::DVars::indent($cont) . "menu \"$name $idx $let\" \"$icon\" {\n"; $ret .= $txt; $ret .= ICE::DVars::indent($cont) . "}\n"; $txt = ''; $let = ''; } } if ($txt ne '') { my $idx = int($acont / $maxitems) + 1; $ret .= ICE::DVars::indent($cont) . "menu \"$name $idx $let\" \"$icon\" {\n"; $ret .= $txt; $ret .= ICE::DVars::indent($cont) . "}\n"; } $ret .= ICE::DVars::indent($cont) . "##### END Splitted menu $name\n" if ($comments); $ret .= ICE::DVars::indent($cont) . "}\n"; } else { $ret .= ICE::DVars::indent($cont) . "menu \"$name\" \"$icon\" {\n"; $ret .= $mntContent; $ret .= ICE::DVars::indent($cont) . "}\n"; } } else { $ret .= $mntContent; } } elsif ($mntContent ne '') { $ret .= $mntContent; } return($ret); } ## read a desktop folder filename sub loadDesktopDir { my ($self, $file) = @_; my $lang = $ENV{LANG}; if ($lang =~ /^(..)/) { $lang = lc $1; } open (F, $file); while() { chomp; if (/^([^=\[\]]+)=\"*(.*)\"*$/) { $self->{uc $1}=$2; } elsif ($lang && $lang ne '' && /^([^=\[\]]+)\[($lang)\]\s*=\"*(.*)\"*$/) { $self->{uc $1}=$3; } } close(F); $self->{FILENAME}=$file; return ($self); } ##################################################################### package ICE::DParser; use XML::Parser; #use Data::Dumper; my ($ind, $file, $mfirst, $mparent, $mcurrent, $tcurrent, $inInclude, $inAnd, $inNot, $inOr, $preOp) = (0); sub new { my ($self, $f) = @_; ($file, $ind) = ($f, 0); ($ind, $file, $mfirst, $mparent, $mcurrent, $tcurrent, $inInclude, $inAnd, $inNot, $inOr, $preOp) = (0, $f); return($self); } sub parse { my ($p) = @_; print STDERR "## Parsing: $file\n" if ($comments); ($mfirst, $mparent, $mcurrent, $tcurrent) = (undef, undef, undef, undef); my $xml = new XML::Parser( Style=>'Objects'); $xml->setHandlers(Start=>\&start, End=>\&end, Char=>\&text); my @tree = @{ $xml->parsefile( $file ) }; return($mfirst); } sub start { ## Start tags handler my ($p, $tag) = @_; $tag = uc $tag; $tcurrent = undef; if ($tag eq 'MENU') { my $parent = $mcurrent; $mfirst = $mcurrent if (!$mfirst); $mcurrent = new ICE::DMenu(); $mcurrent->{PARENT} = $parent; $mcurrent->{XMLFILE} = $file; push @{$parent->{ELEMENTS}}, $mcurrent if ($parent); } elsif ( $tag =~ /$VALID_TAGS/i ) { $tcurrent = $tag; } elsif ( $tag eq 'INCLUDE' ) { $preOp = ''; $inInclude = 1; } elsif ( $tag eq 'AND' ) { $preOp .= "_AND_" ; $inAnd = 1; } elsif ( $tag eq 'NOT' ) { $preOp .= "_NOT_" ; $inNot = 1; } elsif ( $tag eq 'OR' ) { $preOp .= "_OR_"; $inOr = 1; } $ind ++; print ICE::DVars::indent($ind) . "\\\\\\ TAG: $tag PRE: $preOp CUR: $tcurrent CAT: $mcurrent->{CATEGORY}\n" if ($DBG); } sub end { ## End tags handler my ($p, $tag) = @_; $tag = uc $tag; if ($tag eq 'MENU') { $mcurrent->{DONE}=1; $mcurrent = $mcurrent->{PARENT}; } elsif ( $tag eq 'INCLUDE' ) { #$mcurrent->{$tcurrent} = _Include($mcurrent->{$tcurrent}); $mcurrent->{CATEGORY} = _Include($mcurrent->{CATEGORY}); $inInclude = 0; } elsif ( $tag eq 'AND' ) { $preOp =~ s/_AND_\s*$//; $mcurrent->{CATEGORY} = _And($mcurrent->{CATEGORY}); $inAnd = 0; } elsif ( $tag eq 'NOT' ) { $preOp =~ s/_NOT_\s*$//; $mcurrent->{CATEGORY} = _Not($mcurrent->{CATEGORY}); $inNot = 0; } elsif ( $tag eq 'OR' ) { $preOp =~ s/_OR_\s*$//; $mcurrent->{CATEGORY} = _Or($mcurrent->{CATEGORY}); $inOr = 0; } print ICE::DVars::indent($ind) . "/// TAG: $tag PRE: $preOp CUR: $tcurrent CAT: $mcurrent->{CATEGORY}\n" if ($DBG); $ind --; } sub text { ## Text contenr handler my ($p, $data) = @_; if ($tcurrent && $mcurrent) { $data =~ s/[ \t\r\n]+$/ /g; my $tag = uc $tcurrent; if ($inInclude) { $data =~ s/\s+//g; if ($data ne '' ) { $mcurrent->{$tag} .= $preOp; # $mcurrent->{$tag} .= ($tag eq 'CATEGORY') ? " /$data/ " : " $data "; $mcurrent->{$tag} .= ($tag eq 'CATEGORY') ? " /;$data;/ " : " $data "; $preOp = ''; } } else { $mcurrent->{$tag} .= ' ' if ($mcurrent->{$tag}); $mcurrent->{$tag} .= $data; $mcurrent->{$tag} =~ s/ +$//g; } } } sub _Include { my ($txt) = @_; print ICE::DVars::indent($ind) . "OP _Include: $txt " if ($DBG); $txt =~ s/^\s+//g; $txt =~ s/\s+$//g; return $txt if ($txt !~ /./); my @a = split (/[\s]+/,$txt); my $ret = '(' . join(')||(', @a) . ')'; print " -> $ret\n" if ($DBG); return($ret); } sub _And { my ($txt) = @_; print ICE::DVars::indent($ind) . "OP _And: $txt " if ($DBG); if ($txt =~ /^(.*)_AND_\s*(.*)$/) { my ($ini, $end) = ($1, $2); my @a = split (/[\s]+/,$end); $end = '(' . join(')&&(', @a) . ')'; print " -> $ini$end\n" if ($DBG); return "$ini$end"; } print "\n" if ($DBG); return($txt); } sub _Or { my ($txt) = @_; print ICE::DVars::indent($ind) . "OP _Or: $txt " if ($DBG); if ($txt =~ /^(.*)_OR_(.*)$/) { my ($ini, $end) = ($1, $2); my @a = split (/[\s]+/,$end); $end = '(' . join(')||(', @a) . ')'; print " -> $ini$end\n" if ($DBG); return "$ini$end"; } print "\n" if ($DBG); return($txt); } sub _Not { my ($txt) = @_; print ICE::DVars::indent($ind) . "OP _Not: $txt " if ($DBG); if ($txt =~ /^(.*)_NOT_(.*)$/) { my ($ini, $end) = ($1, $2); $end =~ s/^\s+//g; $end =~ s/\s+$//g; my @a = split (/[\s]+/,$end); $end = ' !(' . join(')&&!(', @a) . ')'; print " -> $ini$end\n" if ($DBG); return "$ini$end"; } print "\n" if ($DBG); return($txt); } ##################################################################### package ICE::DApps; #use Data::Dumper; my @apps; sub new() { my ($self, $kdea) = @_; my @files; my $home = $ENV{HOME}; my $regex; my @dirs; if ($kdea == 0) { $regex='/.desktop$/ && !/kde/ && $File::Find::dir !~ /\/kde/'; push @dirs, @DIRS_APPS, "$home/.gnome/apps/"; } elsif ($kdea == 1) { $regex='/.desktop$/ && (/kde/ || $File::Find::dir =~ /\/kde/)'; push @dirs, @DIRS_APPS, @DIRS_APPS_KDE, "$home/.kde/share/applnk"; } elsif ($kdea == 2) { $regex='/.desktop$/'; push @dirs, @DIRS_APPS, @DIRS_APPS_KDE, "$home/.gnome/apps/", "$home/.kde/share/applnk"; } if ($comments) { print STDERR "Looking for apps:\n REGEX: $regex\n DIRS: " . join(" ",@dirs) . "\n"; } push @files, ICE::DVars::findFiles($regex, @dirs); foreach my $file (@files) { my $app = $self->loadDesktopFile($file); $app->{FILE} = $file; if ($file =~ /^(.*)\/+(.+)$/) { $app->{BASENAME}=$2; } push @apps, $app; } return($self); } sub getElements{ my ($self, $menu) = @_; return @apps if (!$menu); my @ret; foreach my $a (@apps) { if (my $r = belongsToCategories($self, $a, $menu) ) { push @ret, $a; #print ICE::DVars::indent($cont) . "> " . $a->{NAME} . " $r \n"; } } return(@ret); } sub getElement { my ($self, $file) = @_; foreach my $a (@apps) { my $basename = $file; if ($file =~ /^(.*)\/+(.+)$/) { $basename = $2; } if ($a->{BASENAME} eq $basename) { return $a; } } } sub loadDesktopFile { my ($self, $file) = @_; my $lang = $ENV{LANG}; if ($lang =~ /^(..)/) { $lang = lc $1; } my $app = new ICE::DApp(); $app->{FILE} = $file; open (F, $file) || return $app; while() { chomp; return ($app) if (defined $app->{EXEC} && /^\s*\[/); if (/^([^=\[\]]+)=(.*)$/) { my $key = uc $1; my $val = $2; if ($val =~ /^\s*\"(.*)\"\s*$/ ) { $val = $1; } $app->{$key}= ($key eq 'CATEGORIES') ? ";$val;" : "$val"; if ($key eq 'EXEC') { my ($exec, $bexec) = ICE::DVars::getAppExec($app); return if (!$exec); } } elsif ($lang && $lang ne '' && /^([^=\[\]]+)\[($lang)\]\s*=\"*(.*)\"*$/) { $app->{uc $1}=$3; } } close(F); return ($app); } sub belongsToCategories { my ($self, $app, $menu) = @_; ## Regular expresion for categories of this menu (ie: ((/;Qt;/)||(/;KDE;/))) my $cat_regexp = $menu->{CATEGORY}; return 0 if ($cat_regexp eq ''); ## Categories for this app (ie: Application;Core my $categories = $app->{CATEGORIES}; my @ok; my $str = '@ok=(grep {' . $cat_regexp . '} (\'' . $categories . '\'));'; eval $str; # OK return "$categories _ $cat_regexp " if ($#ok >= 0); ## Return NOT OK return 0; } ##################################################################### package ICE::DMain; use Data::Dumper; sub mergeFile { my ($ele) = @_; if ($ele->{MERGEFILE}) { my $file = "$ele->{MERGEFILE}"; $file = "$DIR_MENU/$file" if (! -f $file); if ( -f "$file" ) { my $parser = new ICE::DParser($file); my $nele = $parser->parse(); $nele=expandElements ($nele); return ($nele); } } return($ele); } sub expandElements { my ($ele) = @_; return(undef) if (!$ele->{ELEMENTS}); my @elements = @{$ele->{ELEMENTS}}; my @nelements; $ele = mergeFile($ele); foreach my $nele (@elements) { $nele = mergeFile($nele); push @nelements, $nele if ($nele); } $ele->{ELEMENTS}=[@nelements]; return($ele); } my ($root, $uniq, $collapse, $icons, $hideSub, $maxitems, $kde, $kdea)=(undef, 1, 1, 1, 1, 40, 0, 2); sub usage { print <=0); } $root = 0 if (!defined $root); ## Load all xml menus from /etc/xdf/menus @menus = getMenusCfg($kde); exit if ($#menus < 0 && defined($kde) && $kde == 1); ## Load all Icons ICE::DVars::LoadIconFiles(); ## Load all Exec ICE::DVars::LoadExecFiles(); ## Load all application.desktop files $apps = new ICE::DApps($kdea); ## If there aren't xml files, load hardcoded menus in this file. @menus = getMenusCfgDefault() if ($#menus < 0); ## Print menus foreach my $m (@menus) { print "# >> Procesing XML: " . $m->{XMLFILE} . " DIR: " . $m->{DIRECTORY} . " NAM: " . $m->{NAME} . "\n" if ($comments); my $txt = $m->renderMenu($apps, 1, $root, $uniq , $icons, $hideSub, $maxitems); print $txt; } exit if ($argfiles); my @core = getMenuCore(); foreach my $m (@core) { $uniq = 1; $root=0; $icons = 1; print "# >> Core Apps\n" if ($comments); my $txt = $m->renderMenu($apps, 1, $root, $uniq , $icons, $hideSub, $maxitems); print $txt; } my @orphand = getMenuOther(); foreach my $m (@orphand) { $uniq = 1; $root=1; print "# >> Orphand Apps\n" if ($comments); my $txt = $m->renderMenu($apps, 1, $root, $uniq , $icons, $hideSub, $maxitems); print $txt; } exit if ($kde == 1); ## Lxp utilities print "menuprogreload \"_Keyboard layout\" keyboard 300 lxp-icewm-keyboards\n" if (-x "/usr/bin/lxp-icewm-keyboards"); print "menuprogreload \"D_esktop\" desktop 30 lxp-switch-desktop --menu\n" if (-x "/usr/bin/lxp-switch-desktop"); exit; #################################################################################### sub getMenusCfg { my ($kde) = @_; my @ret; foreach my $file (@files) { my $nfile = $file; $nfile =~ s/^.*\///; next if ($filesdone{uc $nfile}); next if (!$kde && $nfile =~ /kde/i); next if (($kde && $kde == 1) && $nfile !~ /kde/i); print STDERR "# Parsing xml file $file\n" if ($comments); my $r; eval { my $parser = new ICE::DParser($file); $r = $parser->parse(); $r = expandElements($r); }; push @ret, $r if ($r); $filesdone{uc $file}=1; } return @ret; } sub getMenuOther { my @ret = ( bless( { 'NAME' => 'Other', 'DONE' => 1, 'CATEGORY' => '/.*/', 'TYPE' => undef, 'ELEMENTS' => [], 'DIRECTORY' => 'Other.directory' }, 'ICE::DMenu' ), ); return @ret; } sub getMenuCore { my @ret = ( bless( { 'NAME' => 'Core', 'DONE' => 1, 'CATEGORY' => '(/Application/)&&(/Core/)', 'TYPE' => undef, 'ELEMENTS' => [], 'DIRECTORY' => 'Core.directory' }, 'ICE::DMenu' ), ); return @ret; } sub getMenusCfgDefault { print "## !! Hardcoded menu ##" if ($comments); my @ret = ( bless( { 'NAME' => 'Applications', 'DONE' => 1, 'CATEGORY' => '', 'TYPE' => undef, 'ELEMENTS' => [ bless( { 'NAME' => 'Accessories', 'DONE' => 1, 'TYPE' => undef, 'ELEMENTS' => [], 'XMLFILE' => '/etc/xdg/menus/applications.menu', 'DIRECTORY' => 'Accessories.directory' }, 'ICE::DMenu' ), bless( { 'NAME' => 'Accessibility', 'DONE' => 1, 'CATEGORY' => '((/;Accessibility;/)&&(!(/;Settings;/)))', 'TYPE' => undef, 'ELEMENTS' => [], 'XMLFILE' => '/etc/xdg/menus/applications.menu', 'DIRECTORY' => 'Accessibility.directory' }, 'ICE::DMenu' ), bless( { 'NAME' => 'Development', 'DONE' => 1, 'CATEGORY' => '(/;Development;/)', 'TYPE' => undef, 'ELEMENTS' => [], 'XMLFILE' => '/etc/xdg/menus/applications.menu', 'DIRECTORY' => 'Development.directory', 'FILENAME' => '(emacs.desktop)' }, 'ICE::DMenu' ), bless( { 'NAME' => 'Education', 'DONE' => 1, 'CATEGORY' => '((/;Education;/))', 'TYPE' => undef, 'ELEMENTS' => [], 'XMLFILE' => '/etc/xdg/menus/applications.menu', 'DIRECTORY' => 'Education.directory' }, 'ICE::DMenu' ), bless( { 'NAME' => 'Games', 'DONE' => 1, 'CATEGORY' => '((/;Game;/))', 'TYPE' => undef, 'ELEMENTS' => [], 'XMLFILE' => '/etc/xdg/menus/applications.menu', 'DIRECTORY' => 'Games.directory' }, 'ICE::DMenu' ), bless( { 'NAME' => 'Graphics', 'DONE' => 1, 'CATEGORY' => '((/;Graphics;/))', 'TYPE' => undef, 'ELEMENTS' => [], 'XMLFILE' => '/etc/xdg/menus/applications.menu', 'DIRECTORY' => 'Graphics.directory' }, 'ICE::DMenu' ), bless( { 'NAME' => 'Internet', 'DONE' => 1, 'CATEGORY' => '((/;Network;/))', 'TYPE' => undef, 'ELEMENTS' => [], 'XMLFILE' => '/etc/xdg/menus/applications.menu', 'DIRECTORY' => 'Internet.directory' }, 'ICE::DMenu' ), bless( { 'NAME' => 'Multimedia', 'DONE' => 1, 'CATEGORY' => '((/;AudioVideo;/))', 'TYPE' => undef, 'ELEMENTS' => [], 'XMLFILE' => '/etc/xdg/menus/applications.menu', 'DIRECTORY' => 'Multimedia.directory' }, 'ICE::DMenu' ), bless( { 'NAME' => 'Office', 'DONE' => 1, 'CATEGORY' => '((/;Office;/))', 'TYPE' => undef, 'ELEMENTS' => [], 'XMLFILE' => '/etc/xdg/menus/applications.menu', 'DIRECTORY' => 'Office.directory' }, 'ICE::DMenu' ), bless( { 'NAME' => 'System', 'DONE' => 1, 'CATEGORY' => '((/;System;/)&&(!(/;Settings;/)))', 'TYPE' => undef, 'ELEMENTS' => [], 'XMLFILE' => '/etc/xdg/menus/applications.menu', 'DIRECTORY' => 'System-Tools.directory' }, 'ICE::DMenu' ), bless( { 'NAME' => 'Other', 'DONE' => 1, 'CATEGORY' => '((/;Application;/)&&(!(/;Core;/))&&(!(/;Settings;/)))', 'TYPE' => undef, 'ELEMENTS' => [], 'XMLFILE' => '/etc/xdg/menus/applications.menu', 'DIRECTORY' => 'Other.directory' }, 'ICE::DMenu' ), bless( { 'NAME' => 'Debian', 'DONE' => 1, 'TYPE' => undef, 'ELEMENTS' => [], 'XMLFILE' => '/etc/xdg/menus/applications.menu', 'MERGEFILE' => 'debian-menu.menu', 'DIRECTORY' => 'Debian.directory' }, 'ICE::DMenu' ) ], 'XMLFILE' => '/etc/xdg/menus/applications.menu', 'DEFAULTDIRECTORYDIRS' => '', 'FILENAME' => '(gnome-app-install.desktop) gnome-app-install.desktop', 'DIRECTORY' => 'Applications.directory' }, 'ICE::DMenu' ), bless( { 'NAME' => 'Preferences', 'DONE' => 1, 'CATEGORY' => '((/;Settings;/)&&(!(()||(/;System;/)||(/;Accessibility;/))))', 'TYPE' => undef, 'ELEMENTS' => [ bless( { 'NAME' => 'Accessibility', 'DONE' => 1, 'CATEGORY' => '((/;Settings;/)&&(/;Accessibility;/))', 'TYPE' => undef, 'ELEMENTS' => [], 'XMLFILE' => '/etc/xdg/menus/preferences.menu', 'DIRECTORY' => 'Settings-Accessibility.directory' }, 'ICE::DMenu' ) ], 'XMLFILE' => '/etc/xdg/menus/preferences.menu', 'DEFAULTDIRECTORYDIRS' => '', 'FILENAME' => 'gnomecc.desktop', 'DIRECTORY' => 'Preferences.directory' }, 'ICE::DMenu' ), bless( { 'NAME' => 'Desktop', 'DONE' => 1, 'CATEGORY' => '', 'TYPE' => undef, 'ELEMENTS' => [ bless( { 'NAME' => 'Preferences', 'DONE' => 1, 'CATEGORY' => '((/;Settings;/)&&(!(()||(/;System;/)||(/;Accessibility;/))))', 'TYPE' => undef, 'ELEMENTS' => [ bless( { 'NAME' => 'Accessibility', 'DONE' => 1, 'CATEGORY' => '((/;Settings;/)&&(/;Accessibility;/))', 'TYPE' => undef, 'ELEMENTS' => [], 'XMLFILE' => 'preferences.menu', 'DIRECTORY' => 'Settings-Accessibility.directory' }, 'ICE::DMenu' ) ], 'XMLFILE' => 'preferences.menu', 'DEFAULTDIRECTORYDIRS' => '', 'FILENAME' => 'gnomecc.desktop', 'DIRECTORY' => 'Preferences.directory' }, 'ICE::DMenu' ), bless( { 'NAME' => 'Administration', 'DONE' => 1, 'CATEGORY' => '((/;Settings;/)&&(/;System;/))', 'TYPE' => undef, 'ELEMENTS' => [], 'XMLFILE' => '/etc/xdg/menus/settings.menu', 'DIRECTORY' => 'System-Settings.directory' }, 'ICE::DMenu' ) ], 'XMLFILE' => '/etc/xdg/menus/settings.menu', 'MERGEFILE' => '', 'DEFAULTDIRECTORYDIRS' => '', 'DIRECTORY' => 'Desktop.directory' }, 'ICE::DMenu' ), ); return @ret; } ## Print applications that no match any menu categories ### my $otherApps = ''; ### my $coreApps = ''; ### foreach my $ap ($apps->getElements()) { ### next if (!$ap || !$ap->{EXEC}); ### ### my ($name, $comment, $icon, $type, $cat) = ### ($ap->{NAME}, $ap->{COMMENT}, $ap->{ICON}, $ap->{TYPE}, $ap->{CATEGORIES}); ### ### my ($exec,$bexec) = ICE::DVars::getAppExec($ap); ### next if (!$exec); ### ### my $cat_regexp = '(/Application/)&&(/Core/)'; ### my @ok; ### my $str = '@ok=(grep {' . $cat_regexp . '} (\'' . $cat . '\'));'; ### eval $str; ### ### $icon = '' if (!$icons && $#ok < 0 ); ### ### my $txt = ''; ### if ($comments) { ### $txt .= ICE::DVars::indent(1) . "# $comment\n"; ### $txt .= ICE::DVars::indent(1) . "# $cat\n"; ### } ### $txt .= ICE::DVars::indent(1) . "prog \"$name\" \"$icon\" $exec\n"; ### ### if ($#ok >= 0) { ### $coreApps .= $txt; ### } else { ### $otherApps .= $txt; ### } ### } ## Orphand applications ### if ($otherApps ne '') { ### print "menu \"_Other\" \"applications-other\" {\n$otherApps\n}\n"; ### } ## Application;Core ### print $coreApps;