Add in dummy AC_CONFIG_HEADERS("") line.
[fvwm-themes.git] / bin / fvwm-themes-menuapp.in
blob210935ee50e61baf006e6644acd3cfaa4f63652e
1 #!@PERL@ -w
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 #-----------------------------------------------------------------------------
19 # Copyright 2000, Olivier Chapuis
20 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Filter this script to pod2man to get a man page:
24 #   pod2man -c "Fvwm Utility" fvwm-themes-menuapp | nroff -man | less -e
25 #-----------------------------------------------------------------------------
27 # this may work but ...
28 #use strict;
29 use Getopt::Long;
31 my $prefix = $ENV{'prefix'} || '@prefix@';
32 my $ROOT_PREFIX = $ENV{'ROOT_PREFIX'} || '@ROOT_PREFIX@';
33 $ROOT_PREFIX = $ENV{'DESTDIR'} if $ENV{'DESTDIR'};
34 my $datadir = "@datadir@";
36 # "system variables"
37 my $version = '@VERSION@';
38 my $fvwmVersion = '@FVWM_VERSION@';
39 my $scriptName = ($0 =~ m:([^/]+)$:, $1);
40 # user
41 my $rcFile = "themes-rc";
42 my $rcFile2 = "$rcFile-2";
43 my $userHome = $ENV{'HOME'} || "./.";
44 my $userDir = $ENV{'FVWM_USERDIR'} || "$userHome/.fvwm";
45 my $persThemeDir = "$userDir/themes/personal";
46 # site
47 my $ftDir = "@FT_DATADIR@";
48 my $siteMenusUser="$ftDir/themes/default/menus-programs";
49 #my $siteDataDir = "$ftDir/data";
50 #my @siteDataFiles = ("$siteDataDir/applications.db");
51 # general
52 my @imagePath = ();
53 my @pathDirs = split(':',$ENV{PATH});
54 my $lang =      $ENV{'LANG'};
56 # options variables
57 my $removePopup = 0;
58 my $buildMenus = 0;
59 my $fvwmMenu = 1;
60 my $block = 0;
61 my $comName = "menuapp"; # via a script "must" be menuapp-pid_of_the_script
62 my $comPid = 0;
63 my $menuFiles = "";
64 my $site = 0;
66 GetOptions(
67         "help"            => \&showHelp,
68         "version"         => \&showVersion,
69         "build-menus"     => \$buildMenus,
70         "site"            => \$site,
71         "remove-popup"    => \$removePopup,
72         "menu-files=s"    => \$menuFiles,
73         "com-mode"        => \$block,
74         "com-name=s"      => \$comName
75 ) || wrongUsage();
77 wrongUsage() unless ($block || $buildMenus);
79 $site || chdir($userDir) || die "No FvwmConfigHome $userDir";
81 my %filesLines = ();    # for storing the contents of the files
82 my %lastLine = ();      # last line of the files
83 my %menuInfo = ();      # General info on a menu
84 my %strMenu = ();       # The menus in a "structured form" (need %menuInfo)
85 my @menuPipeRead = ();  # Some info on the piperead command
86 my @selMenu = ();       # The selection for FvwmScript-Menus
87 my $lastSel = -1;       # Nbr of items in %selMenu -2
88 my @menuFilesList = (); # List of files with menu to look for
89 my @menuFilesListIn = ();
91 if ($buildMenus && $fvwmMenu) {
93         my $change = 1;
95         buildFilesLists();
96         buildstrMenuFromFvwmMenu();
97         checkActionInstrMenu();
99         while ($change != 0) {
100                 $change = 0;
101                 $change = checkMenuInstrMenu();
102                 $change += checkPopupInstrMenu();
103         }
105         checkTitleAndNopInstrMenu();
106         updateLinesInstrMenu();
107         writeFiles();
108         exit(0);
112 if ($fvwmMenu) {
113         buildFilesLists();
114         buildstrMenuFromFvwmMenu();
117 if ($block) {
119         $comPid = $comName;
120         $comPid =~ s/menuapp-//;
121         $comPid = 0 if ($comPid !~ /^\d+$/);
122         getImagePath();
123         comLoop();
127 #-----------------------------------------------------------------------------
128 # For killing FvwmScript-Menus if an error happen in this script!
130 END {
131         if ($block) {
132                 if ($?) {
133                         my $lockFifo = ".tmp-com-lock-" . $comName;
134                         my $inFifo = ".tmp-com-in-" . $comName;
135                         my $message = "fvwm-themes-menuapp: internal error $?\n";
136                         # actually $@ is never defined in END
137                         $message .= "\teval error: $@\n" if $@;
138                         $message .= "\tOS error: $!\n" if $!;
139                         # actually the following is never executed on unix
140                         $message .= "\tOS error 2: $^E\n" if $^E && !($! && $^E eq $!);
141                         
142                         unlink($lockFifo);
143                         unlink($inFifo);
144                         if ($comPid) {
145                                 kill(9,$comPid);
146                                 $message .= "\tkilling FvwmScript-Menus";
147                         }
148                         print STDERR "$message\n"; 
149                 }
150         }
153 #-----------------------------------------------------------------------------
155 # communication loop
157 #-----------------------------------------------------------------------------
159 sub comLoop {
160         
161         my $outFifo = ".tmp-com-out-" . $comName;
162         my $inFifo = ".tmp-com-in-"  . $comName;
163         my $lockFifo = ".tmp-com-lock-" . $comName;
164         my $command = "";
165         my $return = "";
166         my $index = 0;
167         my $menu = "";
168         my $selIndex = 0;
169         my $a = 0;
170         
171         unlink($lockFifo);
172         unlink($inFifo);
173         myMakeFifo($lockFifo);
174         
175         while(1) {
176                 
177                 eval {
178                         local $SIG{ALRM} = \&checkScript;
179                         alarm(10);
180                         # block until com want to communicate
181                         open(LOCK,">$lockFifo") || die "cannot write fifo $lockFifo";
182                         alarm(0);
183                         close(LOCK);
184                 };
185                 if ($@ =~ /^cannot/) {
186                         print STDERR "$comName: cannot write fifo $lockFifo\n";
187                         unlink("$lockFifo");
188                         exit(1);
189                 }
190                 if ($@ =~ /^NoScript/) {
191                         print STDERR "$comName: No more FvwmScript-Menu: exit!\n";
192                         unlink("$lockFifo");
193                         exit(0);
194                 }
195                 if ($@ =~ /^Script/) {
196                         next;
197                 }
198                 
199                 # read the command.
200                 eval {
201                         local $SIG{ALRM} = sub { die "Timeout" };
202                         alarm(10);
203                         # block unless com is ready to write on $outFifo
204                         open(IN,"$outFifo") || die "cannot open $outFifo";
205                         alarm(0);
206                         ($command)=(<IN>);
207                         close(IN);
208                 };
209                 if ($@ =~ /^cannot/) {
210                         print STDERR "$comName: cannot open $outFifo\n";
211                         unlink("$lockFifo");
212                         exit(1);
213                 }
214                 if ($@ =~ /^Timeout/) {
215                         print STDERR "$comName: com gave an invalid unlock!\n";
216                         next;
217                 }
218                 
219                 chomp($command);
220                 if ($command =~ /^menu-items\s+/) {
221                         $command =~ s/^menu-items\s+//;
222                         $return = itemsList($command,-1);
223                 }
224                 elsif ($command =~ /^item\s+/) {
225                         $command =~ s/^item\s+//;
226                         ($menu,$index)=split(':',$command);
227                         $return =  itemsList($menu,$index);
228                 }
229                 elsif ($command =~ /^menus-list$/) {
230                         $return = menusList(-1);
231                 }
232                 elsif ($command =~ /^nbr-of-items\s+/) {
233                         $command =~ s/^nbr-of-items\s+//;
234                         $return = itemsList($command,-2);
235                 }
236                 elsif ($command =~ /^root-menu\s+/) {
237                         $command =~ s/^root-menu\s+//;
238                         $return = rootMenusList($command);
239                 }
240                 elsif ($command =~ /^root-menus-list$/) {
241                         $return = rootMenusList(-1);
242                 }
243                 elsif ($command =~ /^add-or-edit-item\s+/) {
244                         $command =~ s/^add-or-edit-item\s+//;
245                         @ARGV=split(' --',$command);
246                         $a = 1;
247                         while(defined $ARGV[$a]) {      
248                                 $ARGV[$a] =~ s/^(\w\w=)\"/$1/g;
249                                 $ARGV[$a] = "--". $ARGV[$a];
250                                 $ARGV[$a] =~ s/--^\s*\"//g;
251                                 $ARGV[$a] =~ s/\"\s*$//g;
252                                 $a++;
253                         }
254                         $return = addOrEditItem();
255                 }
256                 elsif ($command =~ /^remove-item\s+/) {
257                         $command =~ s/^remove-item\s+//;
258                         ($menu,$index)=split(':',$command);
259                         $return = removeItem($menu,$index);
260                 }
261                 elsif ($command =~ /^move-up\s+/) {
262                         $command =~ s/^move-up\s+//;
263                         ($menu,$index)=split(':',$command);
264                         $return = moveUpDown($menu,$index,"Up");
265                 }
266                 elsif ($command =~ /^move-down\s+/) {
267                         $command =~ s/^move-down\s+//;
268                         ($menu,$index)=split(':',$command);
269                         $return = moveUpDown($menu,$index,"Down");
270                 }
271                 elsif ($command =~ /^selection-items$/) {
272                         $return = selMenuItemsList();
273                 }               
274                 elsif ($command =~ /^add-item-to-selection\s+/) {
275                         $command =~ s/^add-item-to-selection\s+//;
276                         ($menu,$index)=split(':',$command);
277                         $return = addToselMenu($menu,$index);
278                 }
279                 elsif ($command =~ /^remove-sel-item\s+/) {
280                         $command =~ s/^remove-sel-item\s+//;
281                         $return = removeItemInselMenu($command);
282                 }
283                 elsif ($command =~ /^remove-all-sel-item/) {
284                         $return = freeselMenu();
285                 }
286                 elsif ($command =~ /^copy-sel-item\s+/) {
287                         $command =~ s/^copy-sel-item\s+//;
288                         ($menu,$index,$selIndex)=split(':',$command);
289                         $return = insertOneselItem($menu,$index,$selIndex);
290                 }
291                 elsif ($command =~ /^copy-all-sel\s+/) {
292                         $command =~ s/^copy-all-sel\s+//;
293                         ($menu,$index)=split(':',$command);
294                         $return = insertAllselItem($menu,$index);
295                 }
296                 elsif ($command =~ /^try/) {
297                         $return = outPutfilesLines();
298                 }
299                 elsif ($command =~ /^save/) {
300                         writeFiles();
301                         next;
302                 }
303                 elsif ($command eq "exit") {
304                         unlink($lockFifo);
305                         exit(0);
306                 }
307                 else {
308                         print STDERR "$comName: unknown command $command\n";
309                         $return = "0";
310                 }
311                 
312                 myMakeFifo($inFifo);
314                 eval {
315                         local $SIG{ALRM} = sub { die "Timeout" };
316                         alarm(10);
317                         # this line block until com take the answer
318                         open(OUT,">$inFifo") || die "cannot write fifo $inFifo";
319                         alarm(0);
320                         print OUT "ok\n" . $return;
321                         close(OUT);
322                         unlink($inFifo);
323                 };
324                 if ($@ =~ /cannot/) {
325                         print STDERR "$comName: cannot write on fifo $inFifo\n";
326                         unlink($lockFifo);
327                         unlink($inFifo);
328                         exit(1);
329                 }
330                 if ($@ =~ /Timeout/) {
331                         print STDERR "$comName: com do not read my answer!\n";
332                 }
333                 
334         }
337 #----------------------------------------------------------------------------
338 # An alarm handler (called from eval block):
339 sub checkScript {
341         die "Script" unless ($comPid);
343         my $test = 0;
344         my $lockFifo = ".tmp-com-lock-" . $comName;
345         
346         $test = 1 if kill 0 => $comPid;
347         
348         if ($test) { die "Script"; }
349         else { unlink($lockFifo);die "NoScript"; }
352 # ----------------------------------------------------------------------------
354 # ImagePath utils
356 # ----------------------------------------------------------------------------
358 sub getImagePath {
359         # there are more ... (Gnome, kde, ... ?)
360         my @imagePathFiles = ("$userDir/$rcFile2");
361         my ($file,$multiline,$tmp,$im,$line) = ("","","","",""); 
363         for $file (@imagePathFiles) {
364                 open(IN,"$file") || die "Cannot read $file";
365                 $multiline = "";
366                 while(<IN>) {
367                         if ( /\\$/ && ! /\\\\$/) {
368                                 s/\\$//;
369                                 chomp;
370                                 $multiline = $multiline . $_;
371                                 next;
372                         } else {
373                                 $line= $multiline . $_;
374                                 $multiline = "";
375                         }
376                         chomp($line);
377                         $line =~ s/\s+//;
378                         if ($line =~ /^imagepath/i) {
379                                 $line =~ s/^imagepath//i;
380                                 $tmp = getNextQuotedToken(\$line);
381                                 $tmp = `echo $tmp`;
382                                 chomp($tmp);
383                                 if ($tmp =~ /^\+/) {
384                                         $tmp =~ s/\+//g;
385                                         $tmp =~ s/^://;
386                                         $tmp =~ s/:$//;
387                                         if ($im ne "") { $im = $im .":". $tmp; }
388                                         else  { $im = $tmp; }
389                                 }
390                                 elsif ($tmp =~ /\+$/) {
391                                         $tmp =~ s/\+//g;
392                                         $tmp =~ s/^://;
393                                         $tmp =~ s/:$//;
394                                         if ($im ne "") { $im = $tmp .":". $im; }
395                                         else  { $im = $tmp; }
396                                 }
397                                 elsif ($tmp =~ /\+/) {
398                                         my ($tmp1,$tmp2) = split(/\+/,$tmp);
399                                         $tmp1 =~ s/\+//g; $tmp2 =~ s/\+//g;
400                                         $im = $tmp1 .":". $im . ":" . $tmp2;
401                                         $im =~ s/^://; $im =~ s/^:$//;
402                                 }
403                                 else {
404                                         $tmp =~ s/^://;
405                                         $tmp =~ s/:$//;
406                                         $im = $tmp;
407                                 }
408                         }
409                 }
410         }
411         @imagePath = split(':',$im);
414 sub getPrettyIconName {
415         my ($icon) = @_;
416         my $path;
417         foreach $path (@imagePath) {
418                 next if $path eq "";
419                 return $1 if $icon =~ m!^$path/*(.*)$!;
420         }
421         return $icon;
424 # ----------------------------------------------------------------------------
426 # Files buildings
428 # ----------------------------------------------------------------------------
430 sub buildFilesLists {
432         if ($menuFiles ne "") {
433                 @menuFilesList = @menuFilesListIn = split(',',$menuFiles);
434         } else {
435                 if ($site) {
436                         @menuFilesList = ("$siteMenusUser");
437                         @menuFilesListIn = ("$siteMenusUser");
438                         return;
439                 }
440                 @menuFilesList = ("$persThemeDir/menus-programs");
441                 if (! -f "$persThemeDir/menus-programs") {
442                         @menuFilesListIn = ("$siteMenusUser");
443                 } else {
444                         @menuFilesListIn = ("$persThemeDir/menus-programs");
445                 }
446                 push @menuFilesList, "$persThemeDir/menus-extra";
447                 push @menuFilesListIn,"$persThemeDir/menus-extra";
448         }
453 # ----------------------------------------------------------------------------
455 # build a structured menu "strMenu" from a fvwm menu
457 # ----------------------------------------------------------------------------
459 # ----------------------------------------------------------------------------
460 # Main of the building
462 sub buildstrMenuFromFvwmMenu {
463         
464         my ($file,$line,$multiline,$tmpline,$currentMenu,$side,$destroy,$provide)= 
465                 ("","","","","","","");
466         my $outFile;
467         my ($nbr,$index,$utils,$active,$i,$j) = (0,0,0,0,0,0);
469         foreach $file (@menuFilesListIn) {
470                 next if -f $file || "$file" eq "$persThemeDir/menus-extra";
471                 print STDERR "$comName: <<Warning>> No file $file";
472         }
474         for $file (@menuFilesListIn) {
476                 $outFile = $menuFilesList[$j];
477                 $j++;
479                 if (! -f "$file" && "$file" eq "$persThemeDir/menus-extra") {
480                         # creating virtual menus-extra:
481                         # DestroyMenu MenuFvwmPersonal
482                         # AddToMenu MenuFvwmPersonal "Personal" Title
483                         $filesLines{$outFile}[0]{line} = "DestroyMenu MenuFvwmPersonal\n";
484                         $filesLines{$outFile}[1]{line} = 
485                                 "AddToMenu   MenuFvwmPersonal \"Personal\" Title\n";
486                         $menuInfo{"MenuFvwmPersonal"}{destroyline}=
487                                         \$filesLines{$outFile}[0]{line};
488                         addItemMenuInfo("MenuFvwmPersonal","");
489                         $strMenu{"MenuFvwmPersonal"}[0]{line} =
490                                         \$filesLines{$outFile}[1]{line};
491                         addItemstrMenu("MenuFvwmPersonal","Title", "Personal",
492                                 "","","", "", "", "", "",$outFile,"1");
493                         $filesLines{$outFile}[1]{menu} = "MenuFvwmPersonal";
494                         $filesLines{$outFile}[1]{index} = 0;
495                         $lastLine{"$outFile"}= 1;
496                         next;
497                 }
499                 open(IN,"$file") || die "Cannot read $file";
500                 $nbr = 0;
501                 $multiline = "";
503                 while(<IN>) {
505                         if ( /\\$/ && ! /\\\\$/) {
506                                 s/\\$//;
507                                 chomp;
508                                 $multiline = $multiline . $_;
509                                 next;
510                         } else {
511                                 $line= $multiline . $_;
512                                 $multiline = "";
513                         }
515                         $filesLines{$outFile}[$nbr]{line} = $line;
517                         $tmpline = $line;
518                         $tmpline =~ s/^\s*//;
520                         $side ="";
521                         chomp($tmpline);
523                         if (isMenuLine(\$currentMenu,\$tmpline,\$side)) {
525                                 addItemMenuInfo($currentMenu,$side);
526                                 $index=$menuInfo{$currentMenu}{itemsnbr};
527                                 $strMenu{$currentMenu}[$index]{line} =
528                                         \$filesLines{$outFile}[$nbr]{line};
529                                 addItemstrMenu($currentMenu, analyzeMenuLine($tmpline),
530                                         $outFile, $nbr);
531                                 $filesLines{$outFile}[$nbr]{menu} = $currentMenu;
532                                 $filesLines{$outFile}[$nbr]{index} = $index;
534                         } elsif ($tmpline =~ /^DestroyMenu/i) {
536                                 $tmpline =~ s/^DestroyMenu//i;
537                                 $destroy = getNextQuotedToken(\$tmpline);
538                                 if (defined $menuInfo{$destroy}{itemsnbr}) {
539                                         # need to do somthing here ... but what ?
540                                         #undef($menuInfo{$destroy});
541                                         #undef($strMenu{$destroy});
542                                         print STDERR "Warning: Destroying a menu after creation is" . 
543                                                 " not yet supported\n";
544                                 }
545                                 $menuInfo{$destroy}{destroyline}=
546                                         \$filesLines{$outFile}[$nbr]{line};
547                                 $currentMenu = "";
549                         } elsif ($tmpline =~ /^PipeRead/i) {
550                                 $tmpline =~ s/^PipeRead\s+//i;
551                                 ($utils,$i,$provide,$active)=analyzePipeRead($tmpline);
552                                 if ($utils) {
553                                         $menuPipeRead[$i]{line} = \$filesLines{$outFile}[$nbr]{line};
554                                         $menuPipeRead[$i]{provide} = $provide;
555                                         $menuPipeRead[$i]{active} = $active;
556                                 }
557                                 # fixe me!
558                                 $currentMenu = "";
560                         } elsif ($tmpline =~ /^AddTo/i) {
561                                 $currentMenu = "";
562                         }
564                         $nbr++;
566                 }
567                 $lastLine{"$outFile"}=$nbr-1;
568         }
571 #-----------------------------------------------------------------------------
572 # Check if we have a menu line and set the current menu, the side pics and
573 # color and clear some part of the "line".
575 sub isMenuLine {
576         my ($curMenu, $line, $side) = @_;
577         my $s="";
579         $$line =~ s/^\s*//;
581         if ($$curMenu ne "" && $$line =~ /^\+/) {
582                 $$line =~ s/^\+\s*//;
583                 return 1;
584         }
585         if ($$line =~ /^AddToMenu/i) {
586                 $$line =~ s/^AddToMenu\s*//i;
587                 $$curMenu = getNextQuotedToken($line);
588                 $s = $$curMenu;
589                 $s =~ s/@@//g;
590                 if ( $s =~ /@/) {
591                         $s = substr($s,index($s,'@'));
592                         $$side = $s;
593                         $s =~ s/\^/\\^/g;
594                         $$curMenu =~ s/$s//;
595                 }
596                 return 1;
597         }
598         return 0;
601 #-----------------------------------------------------------------------------
602 # Analyze a fvwm menu line
604 sub analyzeMenuLine {
606         my ($line) =  @_;
607         my $trueaction = "";
608         my $useraction = "";
609         my $checkaction = "";
610         my $workingdir = "";
611         my $cdaction = "";
612         my $type = "";
613         my $name = "";
614         my $lefticon = "";
615         my $upicon = "";
616         my $windowtitle = "";
617         my $tmp = "";
619         $line =~ s/^\s*//;
620         return ("empty","","","","","","","","") if ($line eq "");
622         $name = getNextQuotedToken(\$line);
624         # left icon if any
625         $tmp = $name;
626         $tmp =~ s/\%\%//g;
627         if ($tmp =~ /\%/) {
628                 
629                 $lefticon= substr($tmp,index($tmp,'%'));
630                 $lefticon =~ s/^\%//;
631                 $lefticon= substr($lefticon,0,rindex($lefticon,'%'))
632                         if ($lefticon =~ /\%/);
633                 $name =~ s/\%$lefticon\%*//;
634                 $lefticon =~ s/\%//g;
635         }
637         # up icon if any, Need some fixes
638         $tmp = $name;
639         $tmp =~ s/\*\*//;
640         if ($tmp =~ /\*/) {
641                 $upicon=
642                         substr($tmp,index($tmp,'*'),rindex($tmp,'*'));
643                 $name =~ s/$upicon//;
644                 $upicon =~ s/\*//g;
645         }
647         if ($line =~ /^Exec\s+/i) {
648                 $type = "Exec";
649                 $line =~ s/^Exec\s+//i;
650                 $trueaction = $line;
651                 $useraction = $trueaction;
652                 if ($line =~ /^exec/) {
653                         $useraction =~ s/^exec\s+//i;
654                         $checkaction = $useraction;
655                         $checkaction =~ s/^killall\s+//;
656                         $checkaction = substr($checkaction,0,index($checkaction,' '))
657                                 if ($checkaction =~ / /);
658                         $checkaction =~ s/\s//g;
659                 }
660                 elsif ($line =~ /^cd/) {
661                         $useraction =~ s/^cd\s+//i;
662                         $workingdir = substr($useraction,0,index($useraction,';'));
663                         $workingdir =~ s/\s//g;
664                         $workingdir =~ s/\/$//;
665                         $useraction = substr($useraction,index($useraction,"exec")+5);
666                         $useraction =~ s/^\.\///;
667                         $checkaction = $useraction;
668                         $checkaction = substr($checkaction,0,index($checkaction,' '))
669                                 if ($checkaction =~ / /);
670                         $checkaction = "$workingdir/$checkaction";
671                 } else {
672                         $checkaction = $useraction;
673                         $checkaction =~ s/^killall\s+//;
674                         $checkaction = substr($checkaction,0,index($checkaction,' '))
675                                 if ($checkaction =~ / /);
676                         $checkaction =~ s/\s//g;
677                 }
678         }
679         elsif ($line =~ /^Popup\s+/i) {
680                 $type = "Popup";
681                 $trueaction = $line;
682                 $line =~ s/^Popup\s+//i;
683                 $useraction = getNextQuotedToken(\$line);
684         }
685         elsif ($line =~ /^Menu\s+/i) {
686                 $type = "Menu";
687                 $trueaction = $line;
688                 $line =~ s/^Menu\s+//i;
689                 $useraction = getNextQuotedToken(\$line);
690         }
691         elsif ($line =~ /^Nop/i) {
692                 $type = "Nop";
693         }               
694         elsif ($line =~ /^Title/i) {
695                 $type = "Title";
696         }
697         elsif ($line =~ /^FuncFvwmRunInXterm/i) {
698                 $type = "ExecInTerm";
699                 $trueaction = $line;
700                 $line =~ s/^FuncFvwmRunInXterm//i;
701                 $windowtitle = getNextQuotedToken(\$line);
702                 $useraction = getNextQuotedToken(\$line);
703                 $checkaction = $useraction;
704                 $checkaction = substr($checkaction,0,index($checkaction,' '))
705                         if ($checkaction =~ / /);
706         }
707         elsif ($line =~ /^FuncFvwmKillEventAndRun/i) {
708                 $type = "ExecNoSound";
709                 $trueaction = $line;
710                 $line =~ s/^FuncFvwmKillEventAndRun//i;
711                 $useraction = getNextQuotedToken(\$line);
712                 $checkaction = $useraction;
713                 $checkaction = substr($checkaction,0,index($checkaction,' '))
714                         if ($checkaction =~ / /);
715                 }
716                 elsif ($line =~ /^FuncFvwmViewFileTail/i) {
717                 $type = "TailFile";
718                 $trueaction = $line;
719                 $line =~ s/^FuncFvwmViewFileTail//i;
720                 $windowtitle = getNextQuotedToken(\$line);
721                 $useraction = getNextQuotedToken(\$line);
722                 $checkaction = $useraction;
723                 $checkaction = substr($checkaction,0,index($checkaction,' '))
724                         if ($checkaction =~ / /);
725         }
726         elsif ($line =~ /^Restart/i) {
727                 $type = "FvwmCommand";
728                 $trueaction = $line;
729                 $useraction = $trueaction;
730                 $line =~ s/^Restart//i;
731                 $checkaction = getNextQuotedToken(\$line);
732         }
733         else {
734                 $type = "FvwmCommand";
735                 $trueaction = $line;
736                 $useraction = $trueaction;
737         }
739         return ("$type","$name","$lefticon","$upicon","$trueaction","$useraction","$workingdir","$checkaction","$windowtitle");
742 #-----------------------------------------------------------------------------
743 # Quite weak ...
745 sub analyzePipeRead {
747         my ($line) = @_;
748         my $index = "0";
749         my $utils = 0;
750         my $provide = "";
751         my $active = "";
753         if ($line =~ /fvwm-menu-xlock/) {
754                 $utils = 1;
755                 $active = checkApp("xlock");
756                 $line = substr($line,index($line,'name')+4);
757                 $provide = getNextQuotedToken(\$line);
758         }
760         while (defined $menuPipeRead[$index]) { $index++; }
761                         
762         return ($utils,$index,$provide,$active);
765 #----------------------------------------------------------------------------
767 BEGIN {
768         $menuGroupByName = {
769                 "System" => "System",
770                 "Shells" => "Shells",
771                 "ScreenSaver" => "ScreenSaver",
772                 "ScreenSaverModes" => "ScreenSaver::XlockSaver",
773                 "ScreenLockModes" => "ScreenSaver::XlockLock",
774                 "Applications" => "Applications",
775                 "Science" => "Science",
776                 "Editors" => "Editors",
777                 "Internet" => "Internet",
778                 "Graphics" => "Graphics",
779                 "Multimedia" => "Multimedia",
780                 "Games" => "Games",
781                 "Amusements" => "Amusements",
782                 "Xsnow" => "Amusement::Xsnow",
783                 "MesaDemos" => "Amusement::MesaDemos",
784                 "Quit" => "Quit",
785                 "Help" => "Help",
786                 "ManPages" => "ManPages",
787                 "CDE" => "CDE",
788         };
791 sub getGroupByMenuName {
792         my ($menu) = @_;
793         $menu =~ s/^MenuFvwm//;
794         return $menuGroupByName->{$menu};
797 #----------------------------------------------------------------------------
798 # strMenu Clean up
800 sub checkActionInstrMenu {
801         my $key;
802         my $i;
803         
804         foreach $key (keys(%strMenu)) {
805                 for ($i = 0; $i <= $menuInfo{"$key"}{itemsnbr}; $i++) {
806                         if ($strMenu{"$key"}[$i]{checkaction} eq "") {
807                                 $strMenu{"$key"}[$i]{active} = 1 
808                                         if ($strMenu{"$key"}[$i]{type} eq "FvwmCommand");
809                         } else {
810                                 $strMenu{"$key"}[$i]{active} =
811                                         checkApp($strMenu{"$key"}[$i]{checkaction});
812                         }
813                 }
814         }
817 sub checkPopupInstrMenu {
818         my $change = 0;
819         my $i = 0;
820         my $j = 0;
821         my $key;
822         my $test;
823         my $menu;
825         foreach $key (keys(%strMenu)) {
826                 for ($i = 0; $i <= $menuInfo{"$key"}{itemsnbr}; $i++) {
827                         if ($strMenu{"$key"}[$i]{type} eq "Popup" || 
828                                  $strMenu{"$key"}[$i]{type} eq "Menu") {
830                                 $menu =  $strMenu{"$key"}[$i]{useraction};
832                                 $j = 0; $test = 0;
833                                 while(defined $menuPipeRead[$j]) {
834                                         $test = 1 if ($menu eq "$menuPipeRead[$j]{provide}"
835                                                 && $menuPipeRead[$j]{active});
836                                         $j = $j + 1;
837                                 }
839                                 if (!$strMenu{"$key"}[$i]{active} && 
840                                                 ($menuInfo{$menu}{active} || $test)) {
841                                         $strMenu{"$key"}[$i]{active}=1;
842                                         $menuInfo{"$key"}{submenus} .= ","
843                                                 if ($menuInfo{"$key"}{submenus} ne "");
844                                         $menuInfo{"$key"}{submenus} .= $menu;
845                                         $change = 1;
846                                 }
848                         } # if
849                 } # for
850         } # foreach
852         return $change;
855 sub checkMenuInstrMenu {
856         my $test = 0;
857         my $change = 0;
858         my $key;
860         foreach $key (keys(%strMenu)) {
861                 $test = 0;
862                 for ($i = 0; $i <= $menuInfo{"$key"}{itemsnbr}; $i++) {
863                         if ($strMenu{"$key"}[$i]{active} == 1) {
864                                 $test = 1;
865                         }
866                 }
867                 if ($test && !$menuInfo{"$key"}{active}) {
868                         $menuInfo{"$key"}{active} = 1;
869                         $change = 1;    
870                 }
871         }
872         return $change;
875 sub checkTitleAndNopInstrMenu {
876         my $hasActiveAfter = 0;
877         my $ok = 1;
878         my $hasActiveBefore = 0;
879         my $key;
881         foreach $key (keys(%strMenu)) {
882                 for ($i = 0; $i <= $menuInfo{"$key"}{itemsnbr}; $i++) {
883                         $hasActiveBefore = 1 if ($strMenu{"$key"}[$i]{active});
884                         if ($strMenu{"$key"}[$i]{type} =~ /^(Nop|Title|empty)$/) {
885                                 $ok = 1; $j = $i + 1; $hasActiveAfter = 0;
886                                 while($ok && $j <= $menuInfo{"$key"}{itemsnbr}) {
887                                         $hasActiveAfter = 1 if ($ok && $strMenu{"$key"}[$j]{active});
888                                         $ok = 0
889                                                 if $strMenu{"$key"}[$j]{type} =~ /^(Nop|Title)$/;
890                                         $j++;
891                                 }
892                                 if (($i == 0 && ($strMenu{"$key"}[$i]{type} eq "Title" ||
893                                                 $strMenu{"$key"}[$i]{type} eq "empty") && 
894                                                 $menuInfo{"$key"}{active}) ||
895                                                 ($hasActiveBefore && $hasActiveAfter)) {
896                                         $strMenu{"$key"}[$i]{active} = 1;
897                                         $hasActiveBefore = 0;
898                                 }
899                         }
900                 }
901         }
904 sub updateLinesInstrMenu {
905         my $i=0;
906         my $key;
907         
908         foreach $key (keys(%strMenu)) {
910                 if (defined $menuInfo{"$key"}{destroyline}) {
911                         if ($menuInfo{"$key"}{active} == 1) {
912                                 ${$menuInfo{"$key"}{destroyline}} =~ s/^\#//;
913                         } else {
914                                 ${$menuInfo{"$key"}{destroyline}} = "#". 
915                                         ${$menuInfo{"$key"}{destroyline}}
916                                         unless (${$menuInfo{"$key"}{destroyline}} =~ /^\#/);
917                         }
918                 }
919                  
920                 for ($i = 0; $i <= $menuInfo{"$key"}{itemsnbr}; $i++) {
921                         if ($strMenu{"$key"}[$i]{active} == 1) {
922                                 ${$strMenu{"$key"}[$i]{line}} =~ s/^\#//;
923                         } else {
924                                 ${$strMenu{"$key"}[$i]{line}} = "#". ${$strMenu{"$key"}[$i]{line}}
925                                         unless (${$strMenu{"$key"}[$i]{line}} =~ /^\#/);
926                         }
927                 }
929         }
931         $i=0;
932         while(defined $menuPipeRead[$i]) {
933                 if ($menuPipeRead[$i]{active} == 1) {
934                         ${$menuPipeRead[$i]{line}} =~ s/^\#//;
935                 } else {
936                         ${$menuPipeRead[$i]{line}} = "#". ${$menuPipeRead[$i]{line}}
937                                 unless (${$menuPipeRead[$i]{line}} =~ /^\#/);
938                 }
939                 $i++;
940         }
944 # ----------------------------------------------------------------------------
946 # strMenu and filesLines functions
948 # ----------------------------------------------------------------------------
950 # ----------------------------------------------------------------------------
951 # add item to menuInfo 
953 sub addItemMenuInfo {
954         my ($menu,$side) = @_;
955         my $key;
956         my $mIsDef = 0;
957         
958         # need to do that since menu names are not case sensitive
959         foreach $key (keys(%menuInfo)) {
960                 if (eqi($key,$menu) && defined $menuInfo{$menu}{itemsnbr}) {
961                         $mIsDef = 1;
962                         $menu = $key;
963                 }
964         }
966         if ($mIsDef) {
967                 $menuInfo{$menu}{itemsnbr} = $menuInfo{$menu}{itemsnbr}+1;
968                 $menuInfo{$menu}{side} = $side unless ($side eq ""); 
969         } else {
970                 $menuInfo{$menu}{itemsnbr} = 0;
971                 $menuInfo{$menu}{side} = $side;
972                 $menuInfo{$menu}{submenus} = "";
973                 $menuInfo{$menu}{group} = getGroupByMenuName($menu);
974                 $menuInfo{$menu}{active} = 0;
975         }
978 # ----------------------------------------------------------------------------
979 # add an item to strMenu
981 sub addItemstrMenu {
982         
983         my ($menu,$type,$name,$lefticon,$upicon,$trueaction,$useraction,$workingdir,
984                 $checkaction,$windowtitle,$file,$linenbr) = @_;
986         $index = $menuInfo{$menu}{itemsnbr};
987         $strMenu{$menu}[$index]{type} = $type;
988         $strMenu{$menu}[$index]{name} = $name;
989         $strMenu{$menu}[$index]{lefticon} = $lefticon;
990         $strMenu{$menu}[$index]{upicon} = $upicon;
991         $strMenu{$menu}[$index]{trueaction} = $trueaction;
992         $strMenu{$menu}[$index]{useraction} = $useraction;
993         $strMenu{$menu}[$index]{workingdir} = $workingdir;
994         $strMenu{$menu}[$index]{checkaction} = $checkaction;
995         $strMenu{$menu}[$index]{windowtitle} = $windowtitle;
996         $strMenu{$menu}[$index]{group} =  getGroupByMenuName($menu);
997         if ($buildMenus && 
998                 (!($type eq "Popup" || $type eq "Menu") ||
999                  (defined(getGroupByMenuName($useraction)) && $removePopup))) {
1000                 $strMenu{$menu}[$index]{active} = 0;
1001         } else {
1002                 $strMenu{$menu}[$index]{active} = 1;
1003         }
1004         $strMenu{$menu}[$index]{file} = $file;
1005         $strMenu{$menu}[$index]{linenbr} = $linenbr;
1006   
1008         
1009 # ----------------------------------------------------------------------------
1010 # remove an item (comLoop)
1012 sub removeItem {
1013         my ($menu,$item) = @_;
1014         my $line = "";
1015         my $index=0;
1016         my $i;
1017         
1018         return 0 if (! defined $menuInfo{$menu}{itemsnbr});
1019         for ($i = 0; $i <= $menuInfo{$menu}{itemsnbr}; $i++) {
1020                 next if ($strMenu{$menu}[$i]{type} eq "empty");
1021                 $index++;
1022                 if ($item == $index) {
1023                         $strMenu{$menu}[$i]{type} = "empty";
1024                         #$line =~ s/^\s*//;
1025                         if (${$strMenu{$menu}[$i]{line}} =~ /^AddToMenu\s+/i) {
1026                                 ${$strMenu{$menu}[$i]{line}} = "AddToMenu " . $menu . "\n";
1027                         } else {
1028                                 ${$strMenu{$menu}[$i]{line}} = "";
1029                         }
1030                         return 1;
1031                 }
1032         }
1033         return 0;
1036 # ----------------------------------------------------------------------------
1037 # edit or add an item (comLoop)
1038         
1039 sub addOrEditItem {
1040         my $main = shift(@ARGV);  
1041         my $menu = "";
1042         my $i;
1043         my $index;
1044         my $line = "";
1045         my $myItem = "";
1046         my $wdOrwt = "";
1047         my %newItem = (type => "", name => "", lefticon => "", 
1048                 useraction => "", workingdir => "", windowtitle => "");
1050         GetOptions(
1051                 "it:s"  => \$myItem,
1052                 "ti:s"   => \$newItem{type},
1053                 "na:s"   => \$newItem{name},
1054                 "mi:s"  => \$newItem{lefticon},
1055                 "ac:s"   => \$newItem{useraction},
1056                 "wd:s"  => \$wdOrwt,
1057         ) || return 0;
1059         #print STDERR "EorA: $myItem, $newItem{type},$newItem{name}," .
1060         #       "$newItem{lefticon},$newItem{useraction},$wdOrwt,END\n";
1061         ($menu,$index) = split(':',$myItem);
1062         $newItem{type} = getTypeFromPretty($newItem{type});
1063         $newItem{lefticon}=getPrettyIconName($newItem{lefticon})
1064                 if $newItem{lefticon} ne "";
1065         
1066         if (! defined $menuInfo{$menu}{itemsnbr}) {
1067                 $menuInfo{$menu}{itemsnbr} = 0;
1068                 $menuInfo{$menu}{side} = "";
1069                 $menuInfo{$menu}{submenus} = "";
1070                 $menuInfo{$menu}{group} = getGroupByMenuName($menu);
1071                 $menuInfo{$menu}{active} = 1;
1072                 $i = -1;
1073         } else {
1074                 if ($index == 0) { $i = $menuInfo{$menu}{itemsnbr}; }
1075                 else { $i = trueIndex($menu,$index); }
1076         }
1078         if ($newItem{type} eq "Exec") {
1079                         $newItem{workingdir} = $wdOrwt;
1080                 if ($newItem{workingdir} eq "") {
1081                         $newItem{trueaction} = "Exec exec " . $newItem{useraction};
1082                 } else {
1083                         # may have to do more check here ...
1084                         $strMenu{$menu}[$i]{trueaction} = "Exec cd " . 
1085                                 $newItem{workingdir} . "; " . "exec ./" . $newItem{useraction};
1086                 }
1087         }
1088         elsif ($newItem{type} eq "ExecInTerm") {
1089                 $newItem{windowtitle} = $wdOrwt;
1090                 $newItem{trueaction} = "FuncFvwmRunInXterm " . 
1091                         "\"$newItem{windowtitle}\" \"" . $newItem{useraction} . "\"";
1092         }
1093         elsif ($newItem{type} eq "TailFile") {
1094                 $newItem{windowtitle} = $wdOrwt;
1095                 $newItem{trueaction} = "FuncFvwmViewFileTail " . 
1096                         "\"$newItem{windowtitle}\" \"" . $newItem{useraction} . "\"";
1097         }
1098         elsif ($newItem{type} eq "ExecNoSound") {
1099                 $newItem{trueaction} = "FuncFvwmKillEventAndRun " 
1100                         . $newItem{useraction};
1101         }
1102         elsif ($newItem{type} eq "Popup") {
1103                 $newItem{trueaction} = "Popup ". $newItem{useraction};
1104         }
1105         elsif ($newItem{type} eq "Menu") {
1106                 $newItem{trueaction} = "Menu ". $newItem{useraction};
1107         }
1108         elsif ($newItem{type} eq "Nop") {
1109                 $newItem{trueaction} = "Nop";
1110                 $newItem{lefticon} = "";
1111                 $newItem{name} = "";
1112         }
1113         elsif ($newItem{type} eq "Title") {
1114                 $newItem{trueaction} = Title;
1115         }
1116         else {
1117                 $newItem{trueaction} = $newItem{useraction};
1118         }
1120         if ($i <= 0) {
1121                 $line = "AddToMenu " . $menu . " ";
1122         }
1123         elsif ($main ne "A" && 
1124                         ${$strMenu{$menu}[$i]{line}} =~ /^\s*addtomenu/i) { 
1125                 $line = "AddToMenu " . $menu . " ";
1126         } else {
1127                 $line = "+ ";
1128         }
1130         $line .= "\"" . $newItem{name};
1131         $line .= "\%" . $newItem{lefticon} . "\%" if ($newItem{lefticon} ne "");
1132         $line .=  "\" " .  $newItem{trueaction} . "\n";
1134         if ($main eq "A") {
1135                 insertItem($menu,$i,$line,\%newItem);
1136         } else {                
1137                 foreach $key (keys(%newItem)) {
1138                         $strMenu{$menu}[$i]{$key} = $newItem{$key}
1139                 }
1140                 ${$strMenu{$menu}[$i]{line}} = $line;
1141         }
1143         return 1;
1146 # ----------------------------------------------------------------------------
1147 #       insert a new item and line: this is tricky :o) (comLoop)
1149 sub insertItem {
1150         my ($menu,$i,$line,$refHashItem) = @_;
1151         my ($j,$k,$l) = ("0","0","0");
1152         my $tmpLine;
1153         my $tmpFile;
1154         my $tmpMenu;
1155         my $tmpIndex;
1156         my $lineNbr;
1157         my $file;
1158         my $key;
1160         if ($i == -1) {
1161                 # new menu!
1162                 #try to found the good file ...
1163                 foreach $menu (keys(%strMenu)) {
1164                         foreach $key (keys(%strMenu)) {
1165                                 for ($l = 0; $l <= $menuInfo{"$key"}{itemsnbr}; $l++) {
1166                                         $file = $strMenu{"$key"}[$l]{file} 
1167                                                 if (eqi($menu,$strMenu{$key}[$l]{useraction}) &&
1168                                                 ($strMenu{"$key"}[$l]{type} eq "Menu" || 
1169                                                 $strMenu{"$key"}[$l]{type} eq "Popup"));
1170                                 }
1171                         }
1172                         $file = $menuFilesList[0] if (! defined $file);
1173                 }
1174                 #print STDERR "new menu in file $file\n";
1175                 $lineNbr = $lastLine{"$file"}+1;
1176                 $filesLines{"$file"}[$lineNbr]{line} = "\n";
1177                 $lineNbr = $lastLine{"$file"}+2;
1178                 $filesLines{"$file"}[$lineNbr]{line} = "DestroyMenu $menu\n";
1179                 $lineNbr = $lastLine{"$file"} = $lastLine{"$file"}+3;
1180         } else {
1181                 # where we want to insert the new line
1182                 $lineNbr =  $strMenu{$menu}[$i]{linenbr} + 1;
1183                 $file = $strMenu{$menu}[$i]{file};
1185                 # "shift" the menu
1186                 for ($j = $menuInfo{$menu}{itemsnbr}; $j >= ($i+1); $j--) {
1187                         $k=$j+1;
1188                         foreach $key (keys(%{$strMenu{$menu}[$j]})) {
1189                                 if ($key eq "line") {
1190                                         $tmpLine = $strMenu{$menu}[$j]{linenbr};
1191                                         $tmpFile = $strMenu{$menu}[$j]{file};
1192                                         if ("$tmpFile" eq "$file") {
1193                                                 $strMenu{$menu}[$k]{line} = 
1194                                                         \$filesLines{"$file"}[$tmpLine+1]{line};
1195                                         } else {
1196                                                 $strMenu{$menu}[$k]{line}= 
1197                                                         \$filesLines{"$tmpFile"}[$tmpLine]{line};
1198                                         }
1199                                         $filesLines{"$tmpFile"}[$tmpLine]{index}++;
1200                                 } else {
1201                                         $strMenu{$menu}[$k]{$key} = $strMenu{$menu}[$j]{$key};
1202                                 }
1203                         }
1204                 }
1205                 $menuInfo{$menu}{itemsnbr}++;
1207                 # rearrange the menu lines ...
1208                 for ($j = $lastLine{"$file"}; $j >= $lineNbr; $j--) {
1209                         $k = $j+1;
1210                         $filesLines{"$file"}[$k]{line} = $filesLines{"$file"}[$j]{line};
1211                         if (defined $filesLines{"$file"}[$j]{menu}) {
1212                                 $tmpMenu = $filesLines{"$file"}[$k]{menu} = 
1213                                         $filesLines{"$file"}[$j]{menu};
1214                                 $tmpIndex = $filesLines{"$file"}[$k]{index} = 
1215                                         $filesLines{"$file"}[$j]{index};
1216                                 undef($filesLines{"$file"}[$j]{menu});
1217                                 undef($filesLines{"$file"}[$j]{index});
1218                                 $strMenu{$tmpMenu}[$tmpIndex]{linenbr}++;
1219                         }
1220                 }
1221                 $lastLine{"$file"}++;
1222         }
1224         # add the item
1225         $filesLines{"$file"}[$lineNbr]{line} = $line;
1226         $filesLines{"$file"}[$lineNbr]{menu} = $menu;
1227         $filesLines{"$file"}[$lineNbr]{index} = $i+1;
1228         foreach $key (keys(%{$refHashItem})) {
1229                 $strMenu{$menu}[$i+1]{$key} = $$refHashItem{$key} if ($key ne "line");
1230         }
1231         $strMenu{$menu}[$i+1]{line} = \$filesLines{"$file"}[$lineNbr]{line};
1232         $strMenu{$menu}[$i+1]{file} = $file;
1233         $strMenu{$menu}[$i+1]{linenbr} = $lineNbr;      
1236 #-----------------------------------------------------------------------------
1237 # Move up or Down a menu item (comLoop)
1239 sub moveUpDown {
1240         my ($menu,$item,$d) = @_;
1241         my $line = "";
1242         my $index=0;
1243         my $i;
1244         my $j;
1245         my $key;
1246         my $done;
1247         my $tmp;
1248         my $tmp2;
1249         
1250         return 0 if ( !defined $menuInfo{$menu}{itemsnbr} || 
1251                 ($item <2 && $d eq "Up"));
1252         for ($i = 0; $i <= $menuInfo{$menu}{itemsnbr}; $i++) {
1253                 next if ($strMenu{$menu}[$i]{type} eq "empty");
1254                 $index++;
1255                 if ($item == $index) {
1256                         if ($d eq "Down") { 
1257                                 $done = 0; $j = $i; 
1258                                 while(!$done) {
1259                                         $j++;
1260                                         $done = 1 if (!defined $strMenu{$menu}[$j]{type} ||
1261                                                 ($strMenu{$menu}[$j]{type} ne "empty"));
1262                                 }
1263                         }
1264                         return 0 if (!defined $strMenu{$menu}[$j]{type});
1265                         foreach $key (keys(%{$strMenu{$menu}[$i]})) {
1266                                 if ($key eq "line") {
1267                                         $tmp = ${$strMenu{$menu}[$i]{line}};
1268                                         $tmp2 = ${$strMenu{$menu}[$j]{$key}};
1269                                         # we can do better but I am litle bit tied!
1270                                         if ($tmp =~ /^addtomenu/i && $tmp2 !~ /^addtomenu/i) {
1271                                                 $tmp2 =~ s/^\+/AddToMenu $menu/;
1272                                                 #$tmp =~ s/^addtomenu\s+$menu/\+/i;
1273                                         }
1274                                         if ($tmp2 =~ /^addtomenu/i && $tmp !~ /^addtomenu/i) {
1275                                                 $tmp =~ s/^\+/AddToMenu $menu/;
1276                                                 #$tmp2 =~ s/^addtomenu\s+$menu/\+/i;
1277                                         }                                       
1278                                         ${$strMenu{$menu}[$i]{$key}} = $tmp2;
1279                                         ${$strMenu{$menu}[$j]{$key}} = $tmp;
1280                                 } else {
1281                                         $tmp = $strMenu{$menu}[$i]{$key};
1282                                         $strMenu{$menu}[$i]{$key} = $strMenu{$menu}[$j]{$key};
1283                                         $strMenu{$menu}[$j]{$key} = $tmp;
1284                                 }
1285                         }
1286                         return 1;
1287                 }
1288                 if ($d eq "Up") { $j = $i; }
1289         }
1290         return 0;
1293 # ----------------------------------------------------------------------------
1294 # return the true index from the user one (for comLoop func) 
1296 sub trueIndex {
1297         my ($menu,$item) = @_;
1298         my ($done,$index,$i) = ("0","0","0");
1300         while(!$done && defined $strMenu{$menu}[$i]{type}) {
1301                 if ($strMenu{$menu}[$i]{type} eq "empty") { 
1302                         $i++;
1303                         next;
1304                 }
1305                 $index++;
1306                 if ($item == $index) {
1307                         $done = 1;
1308                 } else {
1309                         $i++;
1310                 }
1311         }
1312         # Oops not found ... bad hack
1313         $i = $menuInfo{$menu}{itemsnbr} if (! defined $strMenu{$menu}[$i]{type});
1315         return $i;
1318 # ----------------------------------------------------------------------------
1320 # selMenu function (comLoop)
1322 # ----------------------------------------------------------------------------
1324 # ----------------------------------------------------------------------------
1325 # add an strMenu item to the selection (comLoop) 
1327 sub addToselMenu {
1328         my ($menu,$item) = @_;
1329         my $i;
1330         my $index=0;
1332         return 0 if ( !defined $menuInfo{$menu}{itemsnbr});
1334         for ($i = 0; $i <= $menuInfo{$menu}{itemsnbr}; $i++) {
1335                 next if ($strMenu{$menu}[$i]{type} eq "empty");
1336                 $index++;
1337         
1338                 if ($index == $item) {
1339                         $lastSel++;
1340                         foreach $key (keys(%{$strMenu{$menu}[$i]})) {
1341                                 next if ($key eq "file" || $key eq "linenbr");
1342                                 if ($key eq "line") {
1343                                         $selMenu[$lastSel]{line} = ${$strMenu{$menu}[$i]{line}};
1344                                 } else {
1345                                         $selMenu[$lastSel]{$key} = $strMenu{$menu}[$i]{$key};
1346                                 }
1347                         }
1348                         return 1;
1349                 }
1351         }
1352         return 0;
1356 # ----------------------------------------------------------------------------
1357 # remove a selected item (comLoop)
1358         
1359 sub removeItemInselMenu {
1360         my ($item) = @_;
1361         $item--;
1362         return 0 if (! defined $selMenu[$item]{type} );
1363         removeItemInlist($item,$lastSel,\@{@selMenu});
1364         $lastSel--;
1365         return $lastSel+2;
1368 # ----------------------------------------------------------------------------
1369 # destroy the selection (comLoop)
1371 sub freeselMenu {
1372         my $return = 0;
1373         my $i;
1375         for ($i = $lastSel; $i >= 0; $i--) {
1376                 $return = removeItemInselMenu($i+1);
1377                 return 0 unless ($return);
1378         }
1379         return $return;
1382 # ----------------------------------------------------------------------------
1383 # insert a selItem into strMenu and filesLines (comLoop)
1385 sub insertOneselItem {
1386         my ($menu,$item,$selItem) = @_;
1387         $selItem--;
1388         
1389         return 0 if ($selItem < 0);
1391         if (!defined $menuInfo{$menu}{itemsnbr}) {
1392                 # new menu!
1393                 $menuInfo{$menu}{itemsnbr} = 0;
1394                 $menuInfo{$menu}{side} = "";
1395                 $menuInfo{$menu}{submenus} = "";
1396                 $menuInfo{$menu}{group} = getGroupByMenuName($menu);
1397                 $menuInfo{$menu}{active} = 1;
1398                 $i = -1;
1399         } else {
1400                 # find the true index: i
1401                 if ($item == 0) { $i = $menuInfo{$menu}{itemsnbr}; }
1402                 else { $i = trueIndex($menu,$item); }   
1403         }
1405         # build the new line
1406         $line = $selMenu[$selItem]{line};
1407         chomp($line);
1408         print STDERR "1:".$line . "\n";
1409         if ($line =~ /^AddToMenu\s+/i) {
1410                 $line =~ s/^AddToMenu\s+//i;
1411                 getNextQuotedToken(\$line);
1412         } elsif ($line =~ /^\+\s+/) {
1413                 $line =~ s/^\+\s+//;
1414         }
1415         if ($i == -1) {
1416                 $line = "AddToMenu " . $menu . " " . $line;
1417         } else {
1418                 $line = "+ " . $line;
1419         }
1420         $line .= "\n";
1422         insertItem($menu,$i,$line,$selMenu[$selItem]);
1424         return 1;
1427 # ----------------------------------------------------------------------------
1428 # insert all selItem into strMenu and filesLines (comLoop)
1430 sub insertAllselItem {
1431         my ($menu,$item) = @_;
1432         my $i;
1434         return 0 if ($lastSel == -1);
1436         for ($i = $lastSel; $i >= 0; $i--) {
1437                 insertOneselItem($menu,$item,$i+1);
1438         }
1439         return 1;
1442 #----------------------------------------------------------------------------
1444 # Output functions (for the comLoop)
1446 #----------------------------------------------------------------------------
1448 #----------------------------------------------------------------------------
1449 # Find all the menus or the menus of "index" index in this list (comLoop)
1451 sub menusList() {
1452         my ($index) = @_; 
1453         my $return = "";
1454         my $menu;
1455         my $i = 1;
1457         foreach $menu (keys(%strMenu)) {
1458                 if ($i == $index) { return $menu ."\n"; }
1459                 $i++;           
1460                 $return .= "|" unless ($return eq "");
1461                 $return .= $menu;
1462         }
1464         return $return . "\n";
1467 #----------------------------------------------------------------------------
1468 # Find the "root" menus (comLoop)
1470 sub rootMenusList() {
1471         my ($index) = @_;
1472         my $j = 1;
1473         my $i = 0;
1474         my $isRoot = 1;
1475         my $return = "";
1477         foreach $menu (keys(%strMenu)) {
1478                 $isRoot = 1;
1479                 foreach $key (keys(%strMenu)) {
1480                         for ($i = 0; $i <= $menuInfo{"$key"}{itemsnbr}; $i++) {
1481                                 $isRoot = 0 if (eqi($menu,$strMenu{$key}[$i]{useraction}) &&
1482                                         ($strMenu{"$key"}[$i]{type} eq "Menu" || 
1483                                                 $strMenu{"$key"}[$i]{type} eq "Popup"));
1484                         }
1485                 }
1486            if ($isRoot) {
1487                         if ($j == $index) { return $menu . "\n";}
1488                         $j++;
1489                         $return .= "|" if ( $return ne "");
1490                         $return .= $menu;
1491                 }
1492         }
1493         return $return . "\n";
1496 #----------------------------------------------------------------------------
1497 # selMenu items list (comLoop)
1499 sub selMenuItemsList {
1500         my $return = "";
1501         my $i;
1503         return $return if ($lastSel < 0);
1505         for ($i=0; $i <= $lastSel; $i++) {
1506                 $return .= getTypeForItemsList($selMenu[$i]{type}) . $selMenu[$i]{name};
1507                 $return .= "|" unless ($i == $lastSel);
1508         }
1510         return $return . "\n";
1512                  
1513 #----------------------------------------------------------------------------
1514 # items list (-1), nbr of items (-2) or info on an item (comLoop)
1516 sub itemsList {
1517         my ($menu,$itemIndex) = @_;
1518         my @list =();
1519         my @itemInfo;
1520         my $i;
1521         my $index=0;
1522         my $return = "";
1523         
1524         return 0 if (! defined $menuInfo{$menu}{itemsnbr});
1526         for ($i = 0; $i <= $menuInfo{$menu}{itemsnbr}; $i++) {
1527                 next if ($strMenu{$menu}[$i]{type} eq "empty");
1528                 $index++;
1529                 if ($index == $itemIndex) {
1530                         $return = $strMenu{$menu}[$i]{name}."\n".
1531                                         getPrettyType($strMenu{$menu}[$i]{type})."\n".
1532                                         $strMenu{$menu}[$i]{useraction}."\n".
1533                                         $strMenu{$menu}[$i]{workingdir}."\n".
1534                                         $strMenu{$menu}[$i]{windowtitle}."\n".
1535                                         $strMenu{$menu}[$i]{lefticon}."\n";
1536                         return $return;
1537                 }
1538                 push(@list, getTypeForItemsList($strMenu{$menu}[$i]{type}) . 
1539                         $strMenu{$menu}[$i]{name});
1540         }
1541         if ($itemIndex == -1 && defined $list[0]) {
1542                 $i=0;
1543                 $return = "";
1544                 while(defined $list[$i]) {
1545                         $return .= "|" if ($i);
1546                         $return .= "$list[$i]";
1547                         $i++;
1548                 }
1549                 $return .= "\n";
1550         }
1551         elsif ($itemIndex == -2) {
1552                 $return = $index  ."\n";
1553         }
1555         return $return;
1558 #----------------------------------------------------------------------------
1559 # out put the menu in a variable (comLoop)
1561 sub outPutfilesLines {
1562         my $return = "";
1563         my $i;
1565         foreach $key (keys(%filesLines)) {
1566                 for ($i=0; $i <= $lastLine{$key}; $i++) {
1567                         $return .= $filesLines{"$key"}[$i]{line};
1568                 }
1569         }
1570         return $return;
1575 # ----------------------------------------------------------------------------
1576 # some useful function for the comLoop functions ...
1578 sub getPrettyType {
1579         my ($type) = @_;
1580         if ($type eq "Nop") { $type = "Separator"; }
1581         elsif ($type eq "Exec") {$type = "X Application";}
1582         elsif ($type eq "ExecInTerm") {$type = "Run in a Terminal";}
1583         elsif ($type eq "TailFile") {$type = "Tail File";}
1584         elsif ($type eq "FvwmCommand") {$type = "Fvwm Command";}
1585         elsif ($type eq "Popup") {$type = "Sub Menu";}
1586         return $type;
1589 sub getTypeFromPretty {
1590         my ($type) = @_;
1591         if ($type eq "Separator") { $type = "Nop"; }
1592         elsif ($type eq "X Application") {$type = "Exec";}
1593         elsif ($type eq "Run in a Terminal") {$type = "ExecInTerm";}
1594         elsif ($type eq "Tail File") {$type = "TailFile";}
1595         elsif ($type eq "Fvwm Command") {$type = "FvwmCommand";}
1596         elsif ($type eq "Sub Menu") {$type = "Popup";}
1597         return $type;
1600 sub getTypeForItemsList {
1601         my ($type) = @_;
1602         if ($type eq "Nop")      { $type = "--------------"; }
1603         elsif ($type eq "Popup") { $type = "Sub Menu: ";}
1604         elsif ($type eq "Menu")  { $type = "Menu:    ";}
1605         elsif ($type eq "Title") { $type = "Title:   ";}
1606         else                     { $type = "Action:  "; }
1607         return $type;
1610 #----------------------------------------------------------------------------
1612 # write the menus in the files (comLoop and building)
1614 #----------------------------------------------------------------------------
1616 sub writeFiles {
1618         if (!$site) {
1619                 -d $persThemeDir || mkdir($persThemeDir, 0775) ||
1620                         die "cannot create directory $persThemeDir\n";
1621         }
1622         foreach $key (keys(%filesLines)) {
1623                 open(OUT,">$key") || die "cannot write on $key";
1624                 for ($i=0; $i <= $lastLine{$key}; $i++) {
1625                         print OUT $filesLines{"$key"}[$i]{line};
1626                 }
1627                 close(OUT);
1628         }
1629         return 1;
1632 #----------------------------------------------------------------------------
1634 # for debuging:
1636 #----------------------------------------------------------------------------
1638 sub debugfilesLines {
1640         foreach $key (keys(%filesLines)) {
1641                 for ($i=0; $i <= $lastLine{$key}; $i++) {
1642                         print $filesLines{"$key"}[$i]{line};
1643                 }
1644         }
1647 # ----------------------------------------------------------------------------
1649 # some useful functions
1651 # ----------------------------------------------------------------------------
1653 sub removeItemInlist {
1654         my ($item, $last, $reflist) = @_;
1655         
1656         if ($item == $last) {
1657                 undef ($$reflist[$last]); 
1658                 return 1;
1659         }
1660         for ($i=$item; $i < $last; $i++) {
1661                 $$reflist[$i] = $$reflist[$i+1];
1662         }
1663         undef ($$reflist[$last]);
1664         return 1;
1665 }       
1666                  
1667 sub checkApp {
1668         my($app) = @_;
1669         my $dir ="";
1670         if ($app =~ /^\//) {
1671                 if (-f $app ) { return 1 } # need a fix!
1672         } else {
1673                 foreach $dir (@pathDirs) {
1674                         if ( -x "$dir/$app" ) { return 1 }
1675                 }
1676         }
1677         return 0;
1680 sub myCopyFile {
1681         my ($in,$out)=@_;
1682         open(IN,"$in") || die "cannot open $in";
1683         open(OUT,">$out") || die "cannot create $out";
1684         while(<IN>) { print OUT $_; }
1685         close(IN);
1686         close(OUT);
1689 # returns the next quoted token, modifies the parameter (ref to line)
1690 sub getNextQuotedToken {
1691         my ($line) = @_;
1693         $$line =~ s/^\s+//;
1694         my $quote = '\s';
1695         $quote = substr($$line, 0, 1) if $$line =~ /^["'`]/;
1697         $$line =~ s/^$quote//;
1698         if ($$line =~ /^(.*?)$quote\s*(.*)$/) {
1699                 $$line = $2;
1700                 return $1;
1701         } else {
1702                 my $token = $$line;
1703                 $$line = "";
1704                 return $token;
1705         }
1708 sub eqi {
1709         my ($a,$b) = @_;
1710         $a=lc($a);
1711         $b=lc($b);
1712         if ("$a" eq "$b") {return 1;}
1713         else {return 0;}
1716 sub nei {
1717         my ($a,$b) = @_;
1718         $a=lc($a);
1719         $b=lc($b);
1720         if ($a ne $b) {return 1;}
1721         else {return 0;}
1724 sub myMakeFifo {
1725         my ($fifo) = @_;
1726         system("mkfifo '$fifo'");  # not portable: mknod '$fifo' p
1729 #-----------------------------------------------------------------------------
1731 # The starndard functions
1733 # ----------------------------------------------------------------------------
1735 sub showHelp {
1736         print "The fvwm-themes menus and more utility.\n";
1737         print "Usage: $scriptName --build-menus or --com-mode or --help or --version [OPTIONS]\n";
1738         print "Options:\n";
1739         print "\t--help            show this help and exit\n";
1740         print "\t--version         show the version and exit\n";
1741         print "\t--build-menu      build clean menus\n"; 
1742         print "\t--com-mode        run under communication mode\n";
1743         print "\t--site            use site files\n";
1744         print "\t--menu-files f,f2 files to read and wrote\n";
1745         print "\t--remove-popup    remove certain popup in the building case\n";
1746         print "\t--com-name name   name for communication\n";
1747         exit 0;
1750 sub showVersion {
1751         print "$version\n";
1752         exit 0;
1755 sub wrongUsage {
1756         print STDERR "Try '$scriptName --help' for more information.\n";
1757         exit -1;
1761 __END__
1764 # ----------------------------------------------------------------------------
1766 =head1 NAME
1768 fvwm-themes-menuapp - fvwm-themes menus utility
1770 =head1 SYNOPSIS
1772 B<fvwm-themes-menuapp>
1773 B<--build-menu> or B<--com-mode> orB<--help> or B<--version>
1774 [ B<--site>]
1775 [ B<--menu-files> [file1,file2,...] ]
1776 [ B<--remove-popup>]
1777 [ B<--com-name> name]
1779 =head1 DESCRIPTION
1781 This script is not a user script. It is used by Fvwm-Themes to do differrent
1782 task concerning menu and other related things.
1783 This scripts can do the following:
1785 Parse and rebuild FVWM configuration files to build a clean menu from them:
1786 application not in the path are removed, certain unuseful sub menus and 
1787 separator are removed (--build-menus option).
1789 It can work in a locked way and communicate (via fvwm-themes-com) with
1790 FvwmScript-Menus or any other programs (--com-mode option). See below 
1791 for the list of query that you can ask to fvwm-themes-menuapp via
1792 fvwm-themes-com. 
1794 Plan for the future: use an application data base 
1795 and parse and build (Mini)Icon Styles.
1797 =head1 OPTIONS
1799 You must use (only) one of the following four options:
1801 B<--help>    - show the help and exit
1803 B<--version> - show the version and exit
1805 B<--build-menus> - Cause fvwm-themes-menuapp to build clean menus.
1807 B<--com-mode> Run fvwm-themes-menuapp under the "communication mode".
1809 B<--menu-files> [file1,file2,...] - files which are read and written by 
1810 fvwm-themes-menuapp. By default, fvwm-themes-menuapp will 
1811 read $FT_DATADIR/themes/default/menus-programs with the --site option.
1812 Without the --site option fvwm-themes-menuapp will read menus-programs
1813 and menus-extra  (if found) in the fvwm-themes personal dir:
1814 $FVWM_USERDIR/themes/personal. 
1815 If menus-programs is not found in this directory the site's menus-programs
1816 file is used (the one under $FT_DATADIR). Moreover, if menus-extra is not
1817 found, a virtual such file is created so that the "personal" menus can
1818 be created (MenuFvwmPersonal) in it.
1820 B<--site> - Change the default for the --menu-files option.
1822 B<--remove-popup> - Remove the sub menu popup that popup empty menu (only 
1823 useful with --build-menus). In fact only certain sub menu popup are 
1824 removed.
1826 B<--com-name> name - use name as name for communication with fvwm-themes-com.
1827 By default, "appmenu" is used, but you should use  "appmenu-pid" as name
1828 where pid is the pid of the program that 
1829 want to talk to fvwm-themes-menuapp so that fvwm-themes-menuapp can 
1830 exit if this program exit and so that fvwm-themes-menuapp can kill the program
1831 if an internal error happen in fvwm-themes-menuapp. On the other hand,
1832 if you want to talk with fvwm-themes-menuapp in, say, a terminal you must
1833 not give an name as "menuapp-an_integer" as name.
1835 =head1 COMMUNICATION COMMANDS
1837 Start fvwm-themes-menuapp as:
1839         fvwm-themes-menuapp --com-mode [--com-name=menuapp-pid ...]
1841 Then use fvwm-themes-com as:
1843         fvwm-themes-com --name menuapp[-pid] [--lock-and-get] --message="Command"
1845 where Command is one of the following. All this commands are "lock and
1846 get" but the exit command. A return value of 0 indicate an error.
1848 B<menus-list> - List of the menus.
1850 B<root-menus-list> - List of the "root" menus.
1852 B<root-menus> i - ith root menu.
1854 B<menu-items> menu_name - List of the items of the menu menu_name.
1856 B<item> menu_name:i - Information on the ith item of the menu menu_name.
1858 B<remove> menu_name:i - Remove the ith item of the menu menu_name.
1860 B<move-up> menu_name:i - Move up the ith item of the menu menu_name.
1862 B<move-down> menu_name:i - Move down the ith item of the menu menu_name.
1864 B<add-or-edit-item> X --it='menu_name:i' --t='type' --n='name' --mi='menu-icon'
1865         --wd='working dir or window title'
1866 where X is either A for add or E for edit, see the code for details :)
1868 B<selection-items> - List of the items in the selection.
1870 B<add-item-to-selection> menu_name:i - Add the ith item of the menu menu_name 
1871 to the selection.
1873 B<remove-sel-item> i - Remove the ith item of the selection.
1875 B<remove-all-sel-item> - Remove all the selection items.
1877 B<copy-sel-item> menu_name:i:j - Copy the jth item of the selection after the
1878 ith item of the menu menu_name.
1880 B<copy-all-sel> menu_name:i - Copy all the selection after the
1881 ith item of the menu menu_name.
1883 B<try> - Out put the contents of the files (as soon as possible will run
1884 the good fvwm-themes-config command).
1886 B<save> - wrote back the files
1888 B<exit> - Stop fvwm-themes-menuapp.
1890 =head1 USAGE
1892 When fvwm-themes is installed, fvwm-themes-menuapp is run as:
1894   fvwm-themes-menuapp --site --build-menus --remove-popup
1896 FvwmScript-Menus used (and in fact is based on) fvwm-themes-menuapp. See
1897 this FvwmScript script for examples with the com-mode option.
1899 =head1 AUTHORS
1901 Olivier Chapuis <olivier.chapuis@free.fr>, 5 May 2000.
1903 =head1 COPYING
1905 The script is distributed by the same terms as fvwm itself.
1906 See GNU General Public License for details.
1908 =head1 BUGS
1910 Report bugs to fvwm-themes-devel@lists.sourceforge.net.
1912 =cut
1914 # ----------------------------------------------------------------------------